Type instantiation is excessively deep and possibly infinite.
The last day or two ive had to disable typescript checking or tsignore as i have been getting this within the convex folder for the first time. Needing typecheck=disable to get around it. I had complained about it appearing in the app directory before as a annoyance. I recently added a lot of actions and some scheduled actions or mutations. I managed to get the same errors in the fullstack template by moving folders into the similar structure.
I was seeing this was not suggested.
https://discord.com/channels/1019350475847499849/1187401985301950574
But that's old and i followed the design of the convex ents example. Im doing things 2 deep.
When I was playing around with the fullstack-convex template in its own environment it was triggered when i moved tasks.ts and /tasks/ 1 level deeper
Its possible the saas-starter template does not have enough api or internal calls to triggers this. It seems to require there to be more then 1 on a page or multiple files with more than one call.
I also just noticed that --typecheck=disable is set on saas-starter so maybe that would avoid ever getting the error combined with the lack of api or internal calls.
Tonight i really don't really like typecheck=disable as i made schema changes to indexs and somehow got no warnings of issues till my business partner ran the same code without that flag and several functions were broken.
This fairly reproducible i'm curious if i should just change my file structure or try to spend time creating another fork example of it in a broken state if we want to go down the "this needs to get fixed" path.
I'm also curious if anyone else is naming their stuff like this in a big project.
Thanks
26 Replies
I would avoid using the same name for a directory and file within the same directory. Which Convex ents example did you see this in?
I’ve always been able to resolve this error by explicitly annotating the return type of my Convex function handlers. I’m not aware of this being related to directory structure (although it may well be), and in any case I often have directories and files with the same name, as you’re describing here.
GitHub
saas-starter/convex at main · xixixao/saas-starter
Convex, Clerk, Next.js, Convex Ents. Contribute to xixixao/saas-starter development by creating an account on GitHub.
RJ's solution makes sense, explicitly typing function return values does take care of circular inference issues (which is what this is)
are you spending effort annotating both functions like export function querySphereMember() and export const function = query/mutation(): (used fo api and internal)
cc/ @Michal Srb in case he knows something about the directory structure implications
Yeah we are at like 150 functions and im guessing id have to make types for some of them. unless i lazy annotate with any?
You'll regret annotating as any lol, but yeah that's an option
I would take an alternate file/directory naming scheme over having to explicitly type function return values, personally. Also, you linked to a conversation about the file/directory naming issue that was old, but I think it's still valid.
I've only ever needed to annotate the handlers, specifically. I.e.
My usual experience looks like this:
- Happily code
- Run into this type inference failure (
Type instantiation is excessively deep and possibly infinite.
)
- Furrow brow
- Annotate the Convex function handler(s) that I just wrote/modified
- Return to happily coding
I don't think I've annotated all of them, I just do it when I encounter this issue. Personally, I don't mind this at all because I think explicit type annotations are great. And ensuring that type inference is working properly for these functions is a big part of what makes using Convex queries/mutations/actions so convenient (the type hints/autocompletion).
See https://discord.com/channels/1019350475847499849/1237101416519041158 alsoThere are potentially different issues at play here.
Usually, the "Type instantiation is excessively deep and possibly infinite." error is addressed as documented here:
https://docs.convex.dev/functions/actions#dealing-with-circular-type-inference
But I know that @ampp ran into a different problem, reported in another thread, and we haven't been able to look into that one yet. That was a different type error: https://discord.com/channels/1019350475847499849/1230233206893314111/1230233206893314111
Actions | Convex Developer Hub
Actions can call third party services to do things such as processing a payment
Yeah, im going to try to check through everything to hopefully find when it stops happening, but getting it to happen in the fullstack-convex template without editing function design was making me think its primarily triggered once you get into using sub-sub folders regardless.
It is possible that there is a different cause at play, but I haven't found a consistent repro for it. If you do please share it.
(what does sometime trigger the error is that when you have an issue in your code that makes it impossible for TypeScript to infer the types correctly - moving a file without fixing the code that usess its exports could create such a situation)
Oh interesting, the advice in the docs seems good as well! Annotating the function handlers still feels better to me personally (annotating once at the source rather than multiple times at each call site), but I guess the point is that you just need to annotate some link in the inference cycle to break it
We're refactoring because it just seems like a better overall design and clearer design at scale to not have convex files named the same as folders within /convex/. I do notice how we have two Type instantiation is excessively deep and possibly infinite issues, one that causes convex bundler issues, and one that doesn't.
As soon as i renamed and moved the convex files, my hooks.ts file(where i have the majority of api calls) started showing errors as i had some stuff named improperly so the Type instantiation error on that page was causing other errors to not show. dispite being all usable functions.
Yep, what I have observed since playing with this more is there are two errors that show up in different spots. I figured id provide details. Yes, moving the files in convex with the same names as folders got rid of the "excessively deep error" and earlier i had no functions that had the "implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.". However i was writing more ctx.runQuery actions in actions so i obviously did that:
and "excessively deep" always highlighted at: the api or internal word and only the first one within a function: ctx.runMutation(api.users.createUser, { })
I was thinking of the runMutation and runQuery as effectively the same as useMutation and useQuery but from what i can tell the run variant never knows the return type of what is getting ran so it should always be annotated. Maybe that will help others. I certainly didn't touch those till i needed to with actions.
ctx.runMutation(internal.folder1.folder2.files.save,
runMutation can infer the return type of the mutation, the problem is then using that value as the return type of the action. This creates a cycle:
Note that this applies if even the smallest part of a ctx.run* return value is included in the action return value, even indirectly, which is often the case and makes this harder to hunt down.
I get that side of things, but i was getting the excessively deep issue on functions like await ctx.scheduler.runAfter(0, internal.notifications.createNotification, without any return value. and without requesting the value from the calling function. Its hard to annotate something you dont want the output of.
Is there any chance that there will be a workaround for this limitation?
which particular one? it seems several things were discussed in this thread @magicseth ?
We are returning the value from runAction from an action which breaks the type system
Our current strategy is to pull the handler from the inner action out to its own function and pass it as a handler to one function and then call it directly from the other action. Feels slightly un ergonomic
I haven't had the same degree of issue once i renamed any convex files differently than the folders. But typescript randomly has a seizure often but that seems unrelated. it also seemed like in my hooks file that i was breaking rules by not using the "use" prefix, that also helped with similar issues on front end.
@magicseth sounds like a combination of issues:
1. The annotation to break the inference cycle is required. That's just the nature of how TypeScript does typechecking (and how we provide a single
api
object that has all the return types). I think we'd have to use codegen and split the api and internal to actually be separate, and disallow calling functions via api
, to avoid this issue completely.
2. You need to expose some logic publicly (or to the scheduler) and call it directly. This might look like some ceremony, but it's not too bad in my experience:
You can remove some duplication in the typing of arguments via Infer
, but not doing it gives you the flexibility to evolve this code easily over time (add a check only to the public functions, add more capability only to the helper, etc.)Thanks. Number two is where we landed, but we pass helper directly as the handler instead of awaiting it. Then instead of using runAction from a different action, we just call handler directly. Are there any major reasons to use runAction? We miss out on the validators?
The only good reason to use
ctx.runAction
is when you're switching between runtimes:
https://docs.convex.dev/functions/runtimesRuntimes | Convex Developer Hub
Convex functions can run in two runtimes:
Got it.
Thanks!