#returning using ctx.runQuery gives me type error while db.query doesnt
3 messages · Page 1 of 1 (latest)
This is a well-known TypeScript issue in Convex called "circular type inference." When you use ctx.runQuery (or ctx.runMutation, ctx.runAction, etc.) and return or use the result in a way that TypeScript tries to infer the return type of your function from the result of another Convex function, it can create a circular dependency in the type system. This leads to the error:
'submitRequest' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)
When you use ctx.db.query directly, TypeScript can infer the types from your schema without this circularity, so you don't get the error.
How to fix it:
You need to break the circular inference by explicitly annotating either:
- The return type of your handler function, or
- The type of the value you get from ctx.runQuery.
For example:
export const submitRequest = mutation({
args: { /* ... */ },
handler: async (ctx, args): Promise<Id<"requests">> => {
const dbUser = await ctx.runQuery(internal.users.getUserByExternalId, {
externalId: user.subject,
});
if (!dbUser) throw new Error("User not found");
const newId = await ctx.db.insert("requests", {
spotId,
userId: dbUser._id,
status: "active",
startingDate,
message,
});
return newId;
},
});
Or, annotate the result of ctx.runQuery:
const dbUser: Doc<"users"> | null = await ctx.runQuery(internal.users.getUserByExternalId, {
externalId: user.subject,
});
This tells TypeScript exactly what type to expect, breaking the circular reference and resolving the error. You can read more about this in the Convex documentation: Dealing with circular type inference.