diff --git a/.agents/skills/constructive-graphql/SKILL.md b/.agents/skills/constructive-graphql/SKILL.md index 029173a..7431be2 100644 --- a/.agents/skills/constructive-graphql/SKILL.md +++ b/.agents/skills/constructive-graphql/SKILL.md @@ -69,6 +69,9 @@ const newUser = await db.user.create({ }).execute().unwrap(); ``` +> **Error handling:** `.execute()` returns a discriminated union — it does NOT throw. +> Chain `.execute().unwrap()` to get throw-on-error behavior. See [codegen-error-handling.md](./references/codegen-error-handling.md) for full patterns. + ## Quick Start: Search The simplest way to search — `fullTextSearch` fans a single string to all text-compatible algorithms automatically: @@ -167,7 +170,7 @@ See [search.md](./references/search.md) for the decision matrix and combined que | [codegen-orm-output.md](./references/codegen-orm-output.md) | ORM generated output structure | Understanding what codegen produces | | [codegen-hooks-patterns.md](./references/codegen-hooks-patterns.md) | React Query hook patterns | Using generated hooks in React components | | [codegen-hooks-output.md](./references/codegen-hooks-output.md) | Hooks generated output structure | Understanding hook file structure | -| [codegen-error-handling.md](./references/codegen-error-handling.md) | Error handling patterns | `.unwrap()`, `.unwrapOr()`, discriminated unions | +| [codegen-error-handling.md](./references/codegen-error-handling.md) | **Error handling patterns (read first!)** | `.unwrap()` vs `.execute()`, silent error trap, `QueryResult` discriminated union | | [codegen-relations.md](./references/codegen-relations.md) | Relation queries and M:N mutations | Nested selects, belongsTo, hasMany, manyToMany, composite PKs, `expose_in_api`, add/remove methods | | [codegen-query-keys.md](./references/codegen-query-keys.md) | Query key factory | Cache invalidation, `invalidate.*`, `remove.*` | | [codegen-node-http-adapter.md](./references/codegen-node-http-adapter.md) | Node.js HTTP adapter | Subdomain routing in Node.js | diff --git a/.agents/skills/constructive-graphql/references/codegen-error-handling.md b/.agents/skills/constructive-graphql/references/codegen-error-handling.md index 6741ebc..facdc3b 100644 --- a/.agents/skills/constructive-graphql/references/codegen-error-handling.md +++ b/.agents/skills/constructive-graphql/references/codegen-error-handling.md @@ -2,6 +2,40 @@ Comprehensive guide to handling errors with generated code. +## CRITICAL: `execute()` Does NOT Throw + +**The most common mistake** when using the Constructive ORM is wrapping `.execute()` in a bare `try/catch` and assuming errors will be caught. **They will not.** + +`.execute()` returns a **discriminated union** — it **never throws an exception** on GraphQL or HTTP errors. Instead, it returns `{ ok: false, ... }`. A `try/catch` around `.execute()` will silently swallow errors because no exception is raised. + +```typescript +// BUG: Silent error swallowing — errors are NEVER caught here +try { + const result = await db.user.findMany({ select: { id: true } }).execute(); + // result may be { ok: false, error: {...} } + // but no exception is thrown, so the catch block is skipped entirely + const users = result.value; // users is undefined — silent failure! +} catch (error) { + // This NEVER runs for GraphQL/HTTP errors + console.error(error); +} +``` + +**The fix:** Use `.execute().unwrap()` to get throw-on-error behavior, or check `.ok` explicitly: + +```typescript +// Option A — .execute().unwrap() throws on error (recommended): +const users = await db.user.findMany({ select: { id: true } }).execute().unwrap(); + +// Option B — check .ok for control flow: +const result = await db.user.findMany({ select: { id: true } }).execute(); +if (!result.ok) { + console.error(result.error.message); + return []; +} +return result.value; +``` + ## Discriminated Unions The ORM returns discriminated union results for type-safe error handling: