Draco
Draco2w ago

Error: q implicitly has an 'any' type, & Type instantiation is excessively deep and possibly infinit

Hi guys, I'm pretty new to convex, and I have no idea why this is happening, would be really nice if someone could explain these to me: There's two errors, Type instantiation is excessively deep and possibly infinite. this one is on alooott of random functions, and I checked out the circular type inference stuff, and the error is still there, the other error is Parameter 'q' implicitly has an 'any' type.ts(7006) this one I spent a while with the convex ai thing on the site, and online, couldnt find anything
No description
No description
No description
8 Replies
Draco
DracoOP2w ago
Oh sorry, here they are in text form:
// Helper function to check user permissions
async function validateUserAccess(
ctx: any,
storeId: Id<"stores">,
requiredRoles: StoreRole[]
): Promise<void> {
const user = await getCurrentUserOrThrow(ctx);
const store: Doc<"stores"> | null = await ctx.db.get(storeId);

if (!store) throw new Error("Store not found");

const membership: Doc<"storeMembers">[] = await ctx.db
.query("storeMembers")
.withIndex("by_storeId", q =>
q.eq("storeId", storeId)
)
.collect();

const userMembership = membership.find(m => m.userId === user._id);

if (!userMembership || !requiredRoles.includes(userMembership.role)) {
throw new Error("Unauthorized access");
}
}
// Helper function to check user permissions
async function validateUserAccess(
ctx: any,
storeId: Id<"stores">,
requiredRoles: StoreRole[]
): Promise<void> {
const user = await getCurrentUserOrThrow(ctx);
const store: Doc<"stores"> | null = await ctx.db.get(storeId);

if (!store) throw new Error("Store not found");

const membership: Doc<"storeMembers">[] = await ctx.db
.query("storeMembers")
.withIndex("by_storeId", q =>
q.eq("storeId", storeId)
)
.collect();

const userMembership = membership.find(m => m.userId === user._id);

if (!userMembership || !requiredRoles.includes(userMembership.role)) {
throw new Error("Unauthorized access");
}
}
export async function getCurrentUser(ctx: QueryCtx): Promise<User | null> {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
return null;
}
return await ctx.runQuery(internal.users.userByExternalId, {
externalId: identity.subject,
});
}
export async function getCurrentUser(ctx: QueryCtx): Promise<User | null> {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
return null;
}
return await ctx.runQuery(internal.users.userByExternalId, {
externalId: identity.subject,
});
}
and
export const userByExternalId = internalQuery({
args: { externalId: v.string() },
async handler(
ctx,
{ externalId }: { externalId: string }
): Promise<User | null> {
return await ctx.db
.query("users")
.withIndex("byExternalId", (q) => q.eq("externalId", externalId))
.unique();
},
});
export const userByExternalId = internalQuery({
args: { externalId: v.string() },
async handler(
ctx,
{ externalId }: { externalId: string }
): Promise<User | null> {
return await ctx.db
.query("users")
.withIndex("byExternalId", (q) => q.eq("externalId", externalId))
.unique();
},
});
The circular error is in alot of other places too, seemingly randomly, can't find the issue Such as here at ctx.runQuery(internal.users.userByExternalId)
export const current = query({
args: {},
handler: async (ctx): Promise<User | null> => {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
return null;
}
return await ctx.runQuery(internal.users.userByExternalId, {
externalId: identity.subject,
});
},
});

export const userByExternalId = internalQuery({
args: { externalId: v.string() },
async handler(
ctx,
{ externalId }: { externalId: string }
): Promise<User | null> {
return await ctx.db
.query("users")
.withIndex("byExternalId", (q) => q.eq("externalId", externalId))
.unique();
},
});
export const current = query({
args: {},
handler: async (ctx): Promise<User | null> => {
const identity = await ctx.auth.getUserIdentity();
if (identity === null) {
return null;
}
return await ctx.runQuery(internal.users.userByExternalId, {
externalId: identity.subject,
});
},
});

export const userByExternalId = internalQuery({
args: { externalId: v.string() },
async handler(
ctx,
{ externalId }: { externalId: string }
): Promise<User | null> {
return await ctx.db
.query("users")
.withIndex("byExternalId", (q) => q.eq("externalId", externalId))
.unique();
},
});
ampp
ampp2w ago
In your convex query( functions you usually don't want to run ctx.runQuery because that is what ctx.db is for
WeamonZ
WeamonZ2w ago
hey all you have to do is type the return of your query then you can use your query whenever you want any circular query reference needs to have an handler return type example :
// getCover.ts (returns the cover image of a project)

import { publicQuery, serverQuery } from "../../procedures";
import { internal } from "../../_generated/api";
import { v } from "convex/values";
import { internalQuery } from "../../_generated/server";

type Result = null | {
url: string,
width: number,
height: number,
size: number,
isAlpha: boolean,
}

const args = {
projectId: v.id('projects'),
}

export const _internal = internalQuery({
args,
handler: async (ctx, args): Promise<Result> => {
const project = await ctx.db.get(args.projectId);
if (!project) { throw new Error("Project not found"); }

const resultId = project.resultIds[project.resultIds.length - 1] ?? null;
const result = !resultId ? null :
await ctx.runQuery(internal.router.storage.getImage._internal, { id: resultId })

// HERE I EVEN QUERY AN OTHER INTERNAL QUERY

if (!result) { return null; }

return {
url: result.sizes.thumbnail.url,
width: result.width,
height: result.height,
size: result.size,
isAlpha: result.hasAlpha,
};
}
})

export const public = publicQuery({
args, handler: async (ctx, args): Promise<Result> =>
ctx.runQuery(internal.router.projects.getCover._internal, args)
})

export const server = serverQuery({
args, handler: async (ctx, args): Promise<Result> =>
ctx.runQuery(internal.router.projects.getCover._internal, args)
})
// getCover.ts (returns the cover image of a project)

import { publicQuery, serverQuery } from "../../procedures";
import { internal } from "../../_generated/api";
import { v } from "convex/values";
import { internalQuery } from "../../_generated/server";

type Result = null | {
url: string,
width: number,
height: number,
size: number,
isAlpha: boolean,
}

const args = {
projectId: v.id('projects'),
}

export const _internal = internalQuery({
args,
handler: async (ctx, args): Promise<Result> => {
const project = await ctx.db.get(args.projectId);
if (!project) { throw new Error("Project not found"); }

const resultId = project.resultIds[project.resultIds.length - 1] ?? null;
const result = !resultId ? null :
await ctx.runQuery(internal.router.storage.getImage._internal, { id: resultId })

// HERE I EVEN QUERY AN OTHER INTERNAL QUERY

if (!result) { return null; }

return {
url: result.sizes.thumbnail.url,
width: result.width,
height: result.height,
size: result.size,
isAlpha: result.hasAlpha,
};
}
})

export const public = publicQuery({
args, handler: async (ctx, args): Promise<Result> =>
ctx.runQuery(internal.router.projects.getCover._internal, args)
})

export const server = serverQuery({
args, handler: async (ctx, args): Promise<Result> =>
ctx.runQuery(internal.router.projects.getCover._internal, args)
})
Check your helpers, try to rewrite it step by step as @ampp suggest, you better extract the helpers into internal queries.
erquhart
erquhart2w ago
Other way around, do not use internal queries this way - convert them to helpers instead: https://docs.convex.dev/understanding/best-practices/#use-helper-functions-to-write-shared-code
Best Practices | Convex Developer Hub
This is a list of best practices and common anti-patterns around using Convex.
erquhart
erquhart2w ago
There are solutions for the circular inference problem, but you don't need them here.
Draco
DracoOP2w ago
Can I ask then what internal queries and mutations are for? I'm kinda new to this and it's slightly confusing that runQuery only runs from queries, runMutation only runs from mutations and so on for actions and I kinda thought that internal queries are used when you want to completely separate something onto the server? Is that not how that works? Cuz before I was using t3 env and when I ran a Polar (payment provider) function, it complained that the private env vars shouldn't be imported into the client?
erquhart
erquhart2w ago
It's confusing for sure. 1. Actions were always able to run queries, mutations, or other actions via ctx.run* functions. That generally makes sense, as they're long running, can be used to coordinate paginated queries/mutations, etc. 2. With the advent of components and the isolation between components within an app, all Convex functions needed the ability to run other Convex functions. It has a slight overhead, but is generally worthwhile for enabling the functionality components can provide. 3. Folks have always wanted to do this in Covnex anyway, running functions from other functions just makes sense architecturally. But again, there is currently overhead to this approach, and it's not worth it to incur the slight performance hit and multiple function calls where one would suffice just to organize your backend code more conveniently. 4. Therefore, using helper functions is still the recommended best practice. Also, to clarify: - queries can use ctx.runQuery() only - mutations can use ctx.runQuery() and ctx.runMutation() - actions can run ctx.runQuery(), ctx.runMutation(), and ctx.runAction() Side note, ctx.runAction only makes sense when calling into a different runtime.
Draco
DracoOP2w ago
Ahh I seee Thanks so much for the help everyone

Did you find this page helpful?