Troubleshooting
Common pitfalls developers hit when building with standards, with symptoms and fixes.
Common pitfalls developers hit when building with standards — each entry lists the symptom and the fix.
<Tooltip> must be wrapped in <TooltipProvider>
Tooltips don't render or throw at mount. Wrap your app once with <TooltipProvider> from @stndrds/ui. This is a Radix UI requirement — the provider must exist somewhere above every <Tooltip> in the tree.
Always use the recordsKeys factory for query keys
Cache invalidations don't fire after mutations; stale data persists. Import recordsKeys from @stndrds/react and call it consistently — for example recordsKeys.list({ objectName: "contact" }). Ad-hoc arrays like ["records", "contact"] never match the factory's keys, so invalidation silently fails.
Optimistic updates belong in @stndrds/react hooks, not in @stndrds/ui components
Update logic is duplicated in UI components and rollback on error is inconsistent. Use useUpdateRecord from @stndrds/react — it applies the optimistic update across all caches (detail, grid, list, kanban) and rolls back on error. The save handlers in @stndrds/ui are thin wrappers; never re-implement cache logic inside them.
SchemaClientProvider must be inside QueryClientProvider when you supply your own QueryClient
Hooks throw or render null after mounting. If you pass queryClient={external} to SchemaClientProvider, wrap it with <QueryClientProvider client={external}> first. If you omit the prop, SchemaClientProvider creates its own internal QueryClient and the wrapping is not required.
Never set tool-call limits on spawned subagents
Agent runs cut off mid-task. Do not set maxToolCalls or any equivalent cap on agent definitions. Let the agent run to natural completion — cutting it off mid-task produces partial results that are often harder to recover from than a failed run.
Register relations after their target object
A relation({...}).to("contact") throws at registry registration time. Call registry.register(contact) before registry.register(company). The registry resolves targets at registration, so the target object must already be present.
.required() is a schema rule, not a database constraint
A record is created with a null value despite the schema marking the attribute required. Add a NOT NULL constraint to your Supabase migration for a hard guarantee. .required() enforces validation at SDK level only — the database will still accept null unless you constrain it there.
formula and rollup attributes do not support .required()
TypeScript raises an error when you chain .required() on a formula(...) attribute. Omit .required() on computed attributes. A formula either returns a value or null when its inputs are incomplete — that null is meaningful, so .required() is not applicable.