Troubleshooting Your Plugin
When a plugin misbehaves, the cause is usually one of a handful of things — and most trace back to the plugin loader's startup validation. Here are the common symptoms and where to look.
"Plugin routes return 404"
The plugin most likely failed validation at startup, so its routes were never mounted. Check the startup logs for the plugin validation error, and confirm the manifest, table names, join-table columns, and route prefix are all correct.
"Endpoints return 403 Forbidden on what should be an authenticated request"
The request is probably using the wrong auth type — plugin routes expect the operator JWT, not a machine API key. Confirm you're calling with an operator session, not an engine credential.
"The workflow launched, but resultHandler was never called"
Check workflow_execution.status:
failed_permanent→ the webhook dispatch failed, or n8n never called/complete.completedbut your side-effects didn't happen → yourresultHandlerlikely threw. The core logs the exception and, because the handler runs inside the core's transaction, rolls back all your writes — and it does not retry. Check the logs for your stack trace.
"The workspace status didn't update after completion"
Same root cause: if your resultHandler threw, the core skipped the status transition. Find the plugin's stack trace in the API logs.
"getAvailableWorkflows returns an empty list for a workspace that should have one"
Walk the eligibility checklist: (1) the workflow is_enabled; (2) workflow.belongs_to_entity_id matches the workspace's entity; (3) workflow_eligible_status has a row for (workflow, current status); (4) the dependent configurations (workflow config, service config set) are valid. A disabled dependency anywhere in the chain removes the workflow — see the operator's dependency-chain article.
"My migrations don't run"
Check that plugins/{entity_slug}/migrations/ is spelled exactly right and contains *.sql files. The CI and deploy loops scan by directory name — a typo in the slug means your plugin is silently skipped.
The through-line
Notice how many of these come back to the loader and its validation: a mistyped slug, a missing join-table column, a colliding route prefix. When something's off, the startup logs are almost always the fastest answer — the loader tells you exactly which check failed. (See How the Plugin Loader Discovers & Validates Plugins for the full list of checks.)