name: om-troubleshooter
description: Diagnose and fix common issues in Open Mercato standalone apps — errors, modules not loading, widgets missing, failed migrations, build errors. Triggers — "error", "not working", "broken", "fix", "debug", "404", "500", "module not found". When the trace points into node_modules/@open-mercato/*, STOP and route to om-cto upstream-bug-triage before proposing any fix or PR.
Troubleshooter
Diagnose and fix common issues in Open Mercato standalone apps. Follow the systematic approach: identify symptoms, check common causes, verify fixes.
STOP — Upstream bug routing (read first)
Before reading anything else in this skill, check whether the symptom points at OM core. If yes, route to om-cto/references/upstream-bug-triage.md and do NOT propose a downstream fix or "draft an upstream PR" inline.
Trigger conditions — any of these means STOP and route:
- A stack trace, error log, or breakpoint lands inside
node_modules/@open-mercato/*(or a checked-out@open-mercato/*package). - You found yourself reading source from
node_modules/@open-mercato/*to diagnose. If the diagnostic path went through OM core code, the bug class is "upstream until proven otherwise." - A core function returns wrong data, a contract doesn't match its types/JSDoc, or a widget injection / enricher / interceptor / event subscriber doesn't fire when the wiring looks correct.
- You're about to suggest changes inside
node_modules/@open-mercato/*— even mentally framed as "would need to". - You're about to offer the user a choice that includes "draft an upstream PR" or "patch upstream".
What "route" means concretely:
- Stop the diagnosis hand-off. Do NOT enumerate fix options to the user yet.
- Invoke
om-ctoand loadreferences/upstream-bug-triage.md. Provide the six required inputs (symptom / source location / expected vs actual / repro / proposed workaround sketch / calling agent + task). - Follow the verdict om-cto returns. If the verdict is
confirmed-new-bug, the upstream patch handoff is aWriteto<om_core_path>/agents/tasks/<YYYY-MM-DD>-<slug>/README.md— NOT a PR opened from the consumer-app session, and NOT an entry appended to<om_core_path>/ISSUE_LOG.md. The drain agent picks up by directory listing, not by log scanning.
Why this exists: in past sessions, the troubleshooter found upstream bugs (e.g., raiseCrudError not handling nested error.message in @open-mercato/ui), offered "draft an upstream PR" as a third option alongside local fixes, and on user redirect appended to ISSUE_LOG.md instead of using agents/tasks/<DATE>-<slug>/README.md. Both bypassed the triage protocol. This block is here so it doesn't happen again.
Table of Contents
- Diagnostic Flow
- Module Issues
- Entity & Migration Issues
- API Route Issues
- UI & Widget Issues
- Build & Type Issues
- Extension Issues
- Database Issues
- Quick Diagnostics
1. Diagnostic Flow
When the developer reports a problem, follow this order:
Step 1: Identify the Layer
| Symptom | Layer | Go to |
|---|---|---|
| Module not discovered / route 404 | Module wiring | §2 |
| Database column/table errors | Entity & Migration | §3 |
| API returns 500 / wrong data | API Route | §4 |
| Page blank / component missing | UI & Widget | §5 |
| Build fails / type errors | Build & Type | §6 |
| Enricher/interceptor/widget not working | Extension | §7 |
| Connection refused / query errors | Database | §8 |
Step 2: Check Generated Files
Run these commands first — they fix 60%+ of issues:
yarn generate # Regenerate module discovery files
yarn dev # Restart dev server
If the issue persists after yarn generate, continue to the specific section.
Step 3: Verify the Basics
# Check module is registered
grep '<module_id>' src/modules.ts
# Check generated files exist
ls .mercato/generated/
# Check for TypeScript errors
yarn typecheck
2. Module Issues
Module not found / not loading
Symptoms: 404 on module routes, module not in sidebar, "module not registered" errors
Checklist:
Is the module registered in
src/modules.ts?// Must have this entry: { id: '<module_id>', from: '@app' }Fix: Add the entry and run
yarn generate.Did you run
yarn generate? Check if.mercato/generated/contains your module's entries. Fix: Runyarn generate.Is the module folder named correctly? Must be plural, snake_case:
src/modules/<module_id>/Fix: Rename folder to match module ID.Does
index.tsexportmetadata?export const metadata: ModuleInfo = { name: '<module_id>', ... }Fix: Add the metadata export.
Is the dev server running with latest changes? Fix: Restart with
yarn dev.
Module loads but pages 404
Symptoms: Module appears in generated files but backend pages return 404
Checklist:
Are backend page files in the right location?
- List page:
backend/page.tsx(notbackend/index.tsx) - Detail page:
backend/<entities>/[id].tsx(bracket notation) Fix: Rename to match auto-discovery convention.
- List page:
Do pages export
metadatawithrequireAuth?export const metadata = { requireAuth: true, features: ['<module_id>.view'] }Fix: Add metadata export.
Does the user have the required ACL features? Check
setup.tshasdefaultRoleFeaturesfor the user's role. Fix: Add features to role defaults, re-run setup.
3. Entity & Migration Issues
"Column does not exist" / "Table does not exist"
Symptoms: Database queries fail with missing column/table errors
Checklist:
Did you create a migration after adding/changing the entity?
yarn db:generate # Creates migration fileFix: Run
yarn db:generateto create the migration.Did you apply the migration?
yarn db:migrate # Applies pending migrationsFix: Run
yarn db:migrate.Is the migration file correct? Check
src/modules/<module_id>/migrations/for the latest migration. Verify it has the expected columns and types. Fix: If wrong, delete the migration file, fix the entity, and regenerate.
Migration generation creates unexpected changes
Symptoms: yarn db:generate produces migrations for unrelated modules
Checklist:
Are node_modules up to date?
yarn installDid you modify a core module entity without ejecting? Never edit
node_modules/@open-mercato/*. Fix: Revert changes to node_modules. Use UMES extensions instead, or eject the module.
Entity changes not reflected
Symptoms: Changed entity file but API still returns old schema
Checklist:
- Run
yarn generate— entity discovery is cached - Run
yarn db:generate— schema needs a migration - Run
yarn db:migrate— migration needs to be applied - Restart
yarn dev— server caches entity metadata
4. API Route Issues
Route returns 404
Checklist:
Is the file in the correct path?
src/modules/<module_id>/api/<method>/<route-path>.tsMethod folders:get/,post/,put/,delete/Does it export a default handler?
export default handlerDoes it export
openApi?export const openApi = { summary: '...', tags: ['...'] }API routes without
openApiexport are not discovered.Did you run
yarn generate?
Route returns 500
Checklist:
- Check server logs — look for the actual error message
- Is the entity imported correctly? Verify import path
- Is
organization_idfiltering applied? Required for all tenant-scoped queries - Is the zod schema matching the request body? Schema validation errors return 422, not 500
Route returns 401 / 403
Checklist:
- Is the user authenticated? Check session/token
- Does the user have required features? Check
acl.ts+setup.tsrole mapping - Are features assigned to the user's role? Check role configuration in admin
5. UI & Widget Issues
Backend page is blank
Checklist:
- Does the page have
'use client'directive? Required for pages with interactivity - Check browser console for errors — React rendering errors appear there
- Is the correct import path used? Use
@open-mercato/ui/backend/... - Are API calls using
apiCall/apiCallOrThrow? Never use rawfetch
DataTable shows no data or missing rows
Checklist:
- Is the API path correct? Check
apiPathprop matches actual API route - Is the entity ID correct? Check
entityIdprop - Does the API return data? Test with
curlor browser devtools - Does the user have
viewfeature? Check ACL - Are pagination props wired? Without
page,pageSize,totalCount, andonPageChange, the table only shows the first page with no pagination controls. Check the API returnstotalCountin the response. - Is
organization_idscoping correct? Records created without properorganization_idwon't appear when the API filters by current org - Are records soft-deleted? Records with
deletedAtset are filtered out by default
Sidebar icons broken or wrong
Checklist:
- Are icons using
lucide-reactcomponents? Import fromlucide-react(e.g.,import { Trophy } from 'lucide-react') - AVOID
React.createElement('svg', ...)— inline SVG viaReact.createElementis fragile in bundler contexts and can produce broken icons afteryarn generate - Is the icon defined in
page.meta.ts? Export as part ofmetadata.icon - Did you run
yarn generate? The generator reads icon metadata frompage.meta.ts
Correct pattern:
// page.meta.ts
import { Trophy } from 'lucide-react'
export const metadata = { icon: <Trophy className="size-4" /> }
CrudForm doesn't save
Checklist:
- Check browser network tab — look for the POST/PUT request and response
- Is the zod schema matching the form fields? Mismatched field names cause silent failures
- Are required fields filled? Check form validation
- Does the API route handle the HTTP method? Check
api/post/orapi/put/exists
6. Build & Type Issues
yarn build fails
Checklist:
- Run
yarn typecheckfirst — isolates type errors from build errors - Run
yarn generatefirst — regenerates type-dependent files - Check import paths — use
@open-mercato/<package>/...for framework imports - Check for circular imports — module A importing from module B importing from module A
Type errors after adding a module
Checklist:
- Run
yarn generate— updates generated type files - Check entity imports — use correct relative or package paths
- Check zod schema matches entity — types derived from zod must align
"Module not found" in imports
Checklist:
- Is the package installed? Check
package.jsondependencies - Is the import path correct? Framework packages use
@open-mercato/<package>/... - Is the package built? Run
yarn installto link workspace packages
7. Extension Issues
Response Enricher data not appearing
Checklist:
Is
data/enrichers.tsexportingenrichersarray?export const enrichers = [enricher]Did you run
yarn generate? Enrichers are auto-discoveredIs
targetEntitycorrect? Must match the target module's entity ID exactly (e.g.,customers.personnotcustomers.people)Is the enricher throwing silently? Check
critical: false(default) — errors are swallowed. Temporarily setcritical: trueto surface errors.Check enricher
idis unique — duplicate IDs cause only one to run
Widget not appearing in target module
Checklist:
Is the widget mapped in
injection-table.ts?export const widgetInjections = { '<spot-id>': { widgetId: '<your-widget-id>', priority: 50 }, }Is the spot ID correct? Check the exact format:
- Forms:
crud-form:<entityId>:fields - Tables:
data-table:<tableId>:columns - Menus:
menu:sidebar:main
- Forms:
Does the widget file export default?
export default widgetIs the widget
metadata.idunique? Duplicate IDs cause conflictsDid you run
yarn generate? Widgets are auto-discovered
API Interceptor not running
Checklist:
Is
api/interceptors.tsexportinginterceptorsarray?export { interceptors }Does
targetRoutematch? Check exact route path (without/api/prefix)Does
methodsinclude the HTTP method? e.g.,['GET', 'POST']Is the interceptor throwing instead of returning
{ ok: false }? Errors in interceptors are caught silentlyCheck
priority— lower priority runs first. Another interceptor may be blocking
Component replacement not working
Checklist:
- Is
widgets/components.tsexportingcomponentOverrides? - Is the
componentIdhandle correct? UseComponentReplacementHandleshelpers - For
replacementmode: ispropsSchemaprovided? - Did you run
yarn generate?
8. Database Issues
Connection refused
Checklist:
Is PostgreSQL running?
docker compose ps # Check container status docker compose up -d # Start if stoppedIs
.envconfigured correctly? CheckDATABASE_URLIs the database created?
yarn initialize # Creates DB + first admin
Query timeout / slow queries
Checklist:
- Are indexes present on
organization_idandtenant_id? Check entity has@Index() - Is the query filtering by
organization_id? Missing filter = full table scan - Are enrichers using batch queries? Missing
enrichManycauses N+1
9. Quick Diagnostics
The "Fix Everything" Sequence
When nothing else works, run this full reset sequence:
yarn generate # 1. Regenerate all discovery files
yarn typecheck # 2. Check for type errors
yarn db:generate # 3. Check for pending migrations
yarn db:migrate # 4. Apply any pending migrations
yarn dev # 5. Restart dev server
Common Error → Fix Table
| Error Message | Likely Cause | Fix |
|---|---|---|
Module '<id>' not found |
Not in src/modules.ts |
Add entry, yarn generate |
Table '<name>' does not exist |
Missing migration | yarn db:generate + yarn db:migrate |
Column '<name>' does not exist |
Entity changed without migration | yarn db:generate + yarn db:migrate |
Cannot find module '@open-mercato/...' |
Package not installed | yarn install |
Route not found / 404 |
Missing openApi export or wrong path |
Add export, yarn generate |
401 Unauthorized |
Missing auth or session expired | Check login, check requireAuth |
403 Forbidden |
User lacks required feature | Check acl.ts + setup.ts roles |
422 Unprocessable Entity |
Zod validation failed | Check request body matches schema |
| Widget not showing | Missing injection-table.ts mapping |
Add mapping, yarn generate |
| Enricher data missing | critical: false hiding errors |
Set critical: true temporarily |
| Interceptor not running | Wrong targetRoute or methods |
Check exact route path and methods |
ECONNREFUSED |
Database/service not running | docker compose up -d |
| DataTable shows fewer rows than expected | Missing pagination props or API totalCount |
Wire page/pageSize/totalCount/onPageChange props |
| Sidebar icons broken or wrong | Inline SVG via React.createElement |
Use lucide-react components in page.meta.ts |
yarn generate changes unexpected files |
Stale generated files | Delete .mercato/generated/, re-run |
Rules
- ALWAYS run
yarn generateas first diagnostic step - ALWAYS check server logs / browser console for actual error messages
- NEVER edit files in
.mercato/generated/ornode_modules/ - NEVER assume the issue — verify with actual error output
- Fix the root cause, not the symptom — temporary workarounds become permanent bugs
- NEVER silently patch around suspected OM upstream bugs. See the "STOP — Upstream bug routing" block at the top of this skill for the full protocol. Short version: route to
om-cto/references/upstream-bug-triage.md; the upstream patch handoff is aWriteto<om_core_path>/agents/tasks/<YYYY-MM-DD>-<slug>/README.md, NOT an entry inISSUE_LOG.mdand NOT a PR from the consumer-app session. - When suggesting a fix, include the exact command or code change needed