n8n-io/n8n · error · SyntaxError
Code must export a workflow built with the workflow() SDK fu
Error message
Code must export a workflow built with the workflow() SDK function.
What it means
Thrown by asWorkflowBuilder (called by parseWorkflowCodeToBuilder) when the interpreter's top-level result is neither a WorkflowBuilder (produced by calling workflow()) nor a WorkflowJSON-shaped plain object (something with a `nodes` array). The SDK contract requires that code exports a workflow built via the workflow() SDK function.
Source
Thrown at packages/@n8n/workflow-sdk/src/codegen/parse-workflow-code.ts:707
}
/**
* Coerce an interpreter result into a WorkflowBuilder.
*
* - If the result is already a WorkflowBuilder (produced by the SDK `workflow()` function), return it directly.
* - If the result is a plain object that looks like WorkflowJSON (has a `nodes` array), convert it via `workflow.fromJSON()`.
* - Otherwise, throw with a descriptive error.
*/
function asWorkflowBuilder(result: unknown): WorkflowBuilder {
if (isWorkflowBuilder(result)) {
return result;
}
if (isWorkflowJSON(result)) {
return workflowFn.fromJSON(result);
}
throw new SyntaxError('Code must export a workflow built with the workflow() SDK function.');
}
View on GitHub (pinned to 5ac6606e81)
Solutions
- Ensure the code's `export default` is a call to `workflow()` chained with `.add(...)`: `export default workflow().add(node('X'))`.
- If building from JSON, use `workflow.fromJSON(jsonObj)` and export that.
- Check that the export is not accidentally a node() builder or a plain config object — only a WorkflowBuilder or WorkflowJSON passes the shape guards.
- Verify isWorkflowBuilder/isWorkflowJSON expectations: a WorkflowJSON must have a top-level `nodes` array.
Example fix
// before
export default node('Http').parameters({ url: 'https://x' });
// after
export default workflow()
.add(node('Http').parameters({ url: 'https://x' })); Defensive patterns
Strategy: type-guard
Validate before calling
import { interpretSDKCode } from '@n8n/workflow-sdk/ast-interpreter/interpreter';
function isWorkflowJSON(v: unknown): v is { nodes: unknown[] } {
return typeof v === 'object' && v !== null && Array.isArray((v as { nodes?: unknown[] }).nodes);
}
// After interpretation, verify shape BEFORE calling asWorkflowBuilder
const result = interpretSDKCode(code, sdkFunctions);
if (!isWorkflowBuilder(result) && !isWorkflowJSON(result)) {
throw new Error('Code must export a workflow built with the workflow() SDK function.');
} Type guard
// Guard for the WorkflowJSON shape (has a nodes array)
function isWorkflowJSON(v: unknown): v is { nodes: unknown[]; connections?: unknown } {
return typeof v === 'object' && v !== null && Array.isArray((v as { nodes?: unknown[] }).nodes);
}
// Guard for the WorkflowBuilder shape (duck-typed on .toJSON and .validate)
function isWorkflowBuilder(v: unknown): v is { toJSON: () => unknown; validate: () => unknown } {
return typeof v === 'object' && v !== null
&& typeof (v as { toJSON?: unknown }).toJSON === 'function'
&& typeof (v as { validate?: unknown }).validate === 'function';
} Try / catch
import { parseWorkflowCodeToBuilder } from '@n8n/workflow-sdk/codegen/parse-workflow-code';
try {
const builder = parseWorkflowCodeToBuilder(code);
} catch (e) {
if (e instanceof SyntaxError && /must export a workflow built with the workflow\(\) SDK function/.test(e.message)) {
// instruct: wrap the export in workflow().add(...) or use workflow.fromJSON()
}
throw e;
} Prevention
- Always structure SDK code as `export default workflow().add(...)`.
- If importing from JSON, use `workflow.fromJSON(json)` and export that result.
- Do not export a bare node() result or a config object — only a WorkflowBuilder or WorkflowJSON passes the shape guards.
When it happens
Trigger: SDK code whose `export default` evaluates to: a primitive (string/number/boolean), an array that is not a nodes-array shaped object, a plain object without a `nodes` property, undefined/null, or code that calls an SDK function other than workflow() at the top level without wrapping in workflow().
Common situations: Forgetting to wrap nodes in `workflow().add(...)`; exporting only a single node() result; exporting a configuration object; code that returns a builder that is not the WorkflowBuilder type (e.g., a node builder).
Related errors
- Failed to parse workflow code: ${error.message}. This code c
- Failed to parse workflow code: ${error.message}
- Failed to parse workflow code: ${error.message}. Common caus
- VectorStore "${this.name}" requires an embedding model — set
- topK must be an integer >= 1, got ${k}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/2a3b722f4606a6a9.
Report an issue: GitHub.