WebSocket returns data that doesn't exist in database (CLI works fine)
Problem: The frontend gets prayer data over the Convex WebSocket that does not exist in the database (and sometimes the returned document _id is from another table, e.g. notificationSettings). The same Convex deployment returns correct data when queried via the CLI (e.g. empty array when no prayer exists). So we have a WebSocket vs CLI data mismatch for the same deployment and same logical query.
Key details:
Code: A mutation queries prayers by language and date and returns the first result (or null). Via WebSocket it returns a document; via CLI it returns []/null when no prayer exists.
Schema: Table prayers with index by_language_and_date on language and date. The phantom document’s _id is from table notificationSettings, not prayers.
Observed: Same wrong result with queries, actions, and mutations over WebSocket; different browsers/devices; cache cleared; redeployed. CLI is always correct.
2. Version & environment
Detail Value
Convex version 1.31.5
Convex client version 1.31.5 (convex npm package)
Programming language TypeScript
Runtime (with version) Node v24.13.0
(Framework: Next.js 16.1.3, React 19.2.3)
3. Reproducible scenario (bug)
Steps:
CLI – correct behaviour
Run:
npx convex run "prayers:debugListAllPrayers" '{"date": "2026-02-01", "language": "en"}'
Result: [] (no prayer exists for that date/language).
WebSocket – wrong behaviour
In the app, open the page that calls getPrayerViaMutation with the same date and language.
Result: Frontend receives a prayer object (e.g. title "In the Stillness of Winter's Heart") with an _id and full JSON, as if a prayer existed.
Proof the WebSocket data is wrong
Use the returned _id in a delete (or any) operation that expects a prayers document.
Result: ArgumentValidationError: Found ID "..." from table \notificationSettings
, which does not match the table name in validator v.id("prayers"). So the WebSocket is returning a document from another table, not fromprayers.Minimal code (mutation that shows the mismatch):
export const getPrayerViaMutation = mutation({
args: {
language: v.union(v.literal("en"), v.literal("es"), v.literal("fr"), v.literal("pt")),
date: v.string(),
},
handler: async (ctx, args) => {
const prayer = await ctx.db
.query("prayers")
.withIndex("by_language_and_date", (q) =>
q.eq("language", args.language).eq("date", args.date)
)
.order("desc")
.first();
return prayer;
},
});
Same mutation: correct result via CLI, wrong (phantom/cross-table) result via WebSocket.
4. Network test
(Ran against my DEV deployment; same Convex infrastructure. All checks passed.)
- Performing network test...
5. What I’d like
WebSocket responses should match CLI for the same deployment and same function: return the actual document from the database or null when none exists, and never return a document from a different table.
Account verified – you can check my deployment logs if needed.
Thanks in advance for your help!
