Jamal
Jamal3mo ago

Query/Mutation Error Handling & Transactional Integrity Advice

Hey Convex team and community! We're working on improving the developer experience and type safety of our convex API by standardizing our response types, and we'd love your advice on the idiomatic "Convex way" to approach this. Our goal is to move away from implicitly throwing errors for business logic failures (e.g., "Document not found," "Permission denied") and toward a more explicit API contract. Our initial idea was to adopt a Result type for all our queries and mutations, like Promise<Result<SuccessData, AppError>>. This would make our function signatures self-documenting and allow for type-safe error handling on the client without try/catch boilerplate for every call. However, we then realized a critical detail: throwing an Error is fundamental to how Convex rolls back transactions in mutations. If we stop throwing and instead return an error object (e.g., { status: 'error', ... }), we're concerned we'll lose the automatic ACID guarantees for our failure paths, which is one of the features we love most about Convex. So, our question for the team is: 1. What is the recommended pattern in Convex for returning structured, typed errors from queries and mutations? 2. Is there a way to use a Result-like pattern without breaking transactional rollbacks? For instance, is there a way to manually cancel a transaction within a mutation before returning the error object? 3. Or, is the best practice to create a custom AppError extends Error class, throw it from our functions, and then use type guards on the client to inspect the error caught in a try/catch block? Any insight into best practices here would be super helpful. Thanks so much
8 Replies
Convex Bot
Convex Bot3mo ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
djbalin
djbalin3mo ago
Bump: Also very interested in hearing people's ideas on this :)) both from Convex team and regular mortals
d3m1r
d3m1r3mo ago
++ I would really appreciate input as well
lee
lee3mo ago
Application Errors | Convex Developer Hub
If you have expected ways your functions might fail, you can either return
lee
lee3mo ago
It sounds like you want to throw ConvexError which can have structured data
Jamal
JamalOP3mo ago
Yes, we currently do this. I guess my core concern is not really a convex problem but more of a typescript one. Errors are not apart of a function return type in typescript and the client as no way to know what type of errors are thrown. I think the best solution is to create a catchAll hook on the client that wraps our querys and mutations and we can parse the structured data and handle it.
Riki
Riki3mo ago
@Jamal I exactly have the same problem as you. After having worked with Convex for more than a year, this is still the part I am not sure what is the best pattern. I think it would be nice to somehow be able to do call it that way the frontend: api.function._errors that is an exported object that would need to be defined
Jamal
JamalOP3mo ago
Yeah, I wish there was a way to programmatically cancel the database transaction then it would be possible to use errors as values and not throw them.

Did you find this page helpful?