| 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-cto and load references/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 a Write to <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
yarn dev
If the issue persists after yarn generate, continue to the specific section.
Step 3: Verify the Basics
grep '<module_id>' src/modules.ts
ls .mercato/generated/
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?
{ 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: Run yarn 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.ts export metadata?
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 (not backend/index.tsx)
- Detail page:
backend/<entities>/[id].tsx (bracket notation)
Fix: Rename to match auto-discovery convention.
-
Do pages export metadata with requireAuth?
export const metadata = { requireAuth: true, features: ['<module_id>.view'] }
Fix: Add metadata export.
-
Does the user have the required ACL features?
Check setup.ts has defaultRoleFeatures for 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
Fix: Run yarn db:generate to create the migration.
-
Did you apply the migration?
yarn db:migrate
Fix: 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 install
-
Did 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>.ts
Method folders: get/, post/, put/, delete/
-
Does it export a default handler?
export default handler
-
Does it export openApi?
export const openApi = { summary: '...', tags: ['...'] }
API routes without openApi export 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_id filtering 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.ts role 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 raw fetch
DataTable shows no data or missing rows
Checklist:
- Is the API path correct? Check
apiPath prop matches actual API route
- Is the entity ID correct? Check
entityId prop
- Does the API return data? Test with
curl or browser devtools
- Does the user have
view feature? Check ACL
- Are pagination props wired? Without
page, pageSize, totalCount, and onPageChange, the table only shows the first page with no pagination controls. Check the API returns totalCount in the response.
- Is
organization_id scoping correct? Records created without proper organization_id won't appear when the API filters by current org
- Are records soft-deleted? Records with
deletedAt set are filtered out by default
Sidebar icons broken or wrong
Checklist:
- Are icons using
lucide-react components? Import from lucide-react (e.g., import { Trophy } from 'lucide-react')
- AVOID
React.createElement('svg', ...) — inline SVG via React.createElement is fragile in bundler contexts and can produce broken icons after yarn generate
- Is the icon defined in
page.meta.ts? Export as part of metadata.icon
- Did you run
yarn generate? The generator reads icon metadata from page.meta.ts
Correct pattern:
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/ or api/put/ exists
6. Build & Type Issues
yarn build fails
Checklist:
- Run
yarn typecheck first — isolates type errors from build errors
- Run
yarn generate first — 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.json dependencies
- Is the import path correct? Framework packages use
@open-mercato/<package>/...
- Is the package built? Run
yarn install to link workspace packages
7. Extension Issues
Response Enricher data not appearing
Checklist:
-
Is data/enrichers.ts exporting enrichers array?
export const enrichers = [enricher]
-
Did you run yarn generate? Enrichers are auto-discovered
-
Is targetEntity correct? Must match the target module's entity ID exactly
(e.g., customers.person not customers.people)
-
Is the enricher throwing silently? Check critical: false (default) — errors are swallowed.
Temporarily set critical: true to surface errors.
-
Check enricher id is 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
-
Does the widget file export default?
export default widget
-
Is the widget metadata.id unique? Duplicate IDs cause conflicts
-
Did you run yarn generate? Widgets are auto-discovered
API Interceptor not running
Checklist:
-
Is api/interceptors.ts exporting interceptors array?
export { interceptors }
-
Does targetRoute match? Check exact route path (without /api/ prefix)
-
Does methods include the HTTP method? e.g., ['GET', 'POST']
-
Is the interceptor throwing instead of returning { ok: false }?
Errors in interceptors are caught silently
-
Check priority — lower priority runs first. Another interceptor may be blocking
Component replacement not working
Checklist:
- Is
widgets/components.ts exporting componentOverrides?
- Is the
componentId handle correct? Use ComponentReplacementHandles helpers
- For
replacement mode: is propsSchema provided?
- Did you run
yarn generate?
8. Database Issues
Connection refused
Checklist:
-
Is PostgreSQL running?
docker compose ps
docker compose up -d
-
Is .env configured correctly? Check DATABASE_URL
-
Is the database created?
yarn initialize
Query timeout / slow queries
Checklist:
- Are indexes present on
organization_id and tenant_id? Check entity has @Index()
- Is the query filtering by
organization_id? Missing filter = full table scan
- Are enrichers using batch queries? Missing
enrichMany causes N+1
9. Quick Diagnostics
The "Fix Everything" Sequence
When nothing else works, run this full reset sequence:
yarn generate
yarn typecheck
yarn db:generate
yarn db:migrate
yarn dev
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 generate as first diagnostic step
- ALWAYS check server logs / browser console for actual error messages
- NEVER edit files in
.mercato/generated/ or node_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 a Write to <om_core_path>/agents/tasks/<YYYY-MM-DD>-<slug>/README.md, NOT an entry in ISSUE_LOG.md and NOT a PR from the consumer-app session.
- When suggesting a fix, include the exact command or code change needed