n8n-io/n8n · error · SyntaxError
Failed to parse workflow code: ${error.message}
Error message
Failed to parse workflow code: ${error.message} What it means
Thrown by parseWorkflowCode when interpretSDKCode raises an InterpreterError whose message includes 'reserved SDK function name'. This specific case is re-thrown as a SyntaxError WITHOUT the 'common causes' hint, because it is a naming conflict, not a typo. Reserved names are the entries in ALLOWED_SDK_FUNCTIONS (workflow, node, trigger, ifElse, etc.).
Source
Thrown at packages/@n8n/workflow-sdk/src/codegen/parse-workflow-code.ts:631
try {
// Use AST interpreter instead of new Function() for security
const wf = interpretSDKCode(executableCode, sdkFunctions);
// Return the JSON representation
return (wf as { toJSON: () => WorkflowJSON }).toJSON();
} catch (error) {
if (error instanceof SecurityError) {
// Re-throw security errors with more context
throw new SyntaxError(
`Failed to parse workflow code: ${error.message}. ` +
'This code contains patterns that are not allowed for security reasons.',
);
}
if (error instanceof InterpreterError) {
// Check for reserved SDK name conflicts
if (error.message.includes('reserved SDK function name')) {
throw new SyntaxError(`Failed to parse workflow code: ${error.message}`);
}
// Convert interpreter errors to syntax errors for consistent API
throw new SyntaxError(
`Failed to parse workflow code: ${error.message}. ` +
'Common causes include unclosed template literals, missing commas, or unbalanced brackets.',
);
}
throw error;
}
}
/**
* Parses generated TypeScript SDK code and returns the WorkflowBuilder.
* This allows callers to validate the graph structure before converting to JSON.
*
* Uses a secure AST-based interpreter instead of eval/new Function().
*
* @param code - TypeScript code generated by generateWorkflowCode()View on GitHub (pinned to 5ac6606e81)
Solutions
- Rename the local variable to something that is not a reserved SDK function name (e.g., `node` → `myNode`, `workflow` → `wf`).
- Check ALLOWED_SDK_FUNCTIONS in validators.ts for the full reserved list; core builders (workflow, node, trigger, sticky, placeholder, newCredential) and control-flow (ifElse, switchCase, merge, splitInBatches, nextBatch) are NOT auto-renameable.
- Subnode builder names (languageModel, memory, tool, etc.) ARE auto-renameable, so those will not trigger this error.
Example fix
// before const node = 'Http'; export default workflow().add(/* referencing node */); // after const nodeName = 'Http'; export default workflow().add(node(nodeName));
Defensive patterns
Strategy: validation
Validate before calling
import { ALLOWED_SDK_FUNCTIONS, AUTO_RENAMEABLE_SDK_FUNCTIONS } from '@n8n/workflow-sdk/ast-interpreter/validators';
function findReservedNameCollisions(code: string): string[] {
const hardReserved = new Set(
[...ALLOWED_SDK_FUNCTIONS].filter((n) => !AUTO_RENAMEABLE_SDK_FUNCTIONS.has(n))
);
const hits = new Set<string>();
for (const name of hardReserved) {
const re = new RegExp(`\\b(?:const|let|var)\\s+${name}\\b`);
if (re.test(code)) hits.add(name);
}
return [...hits];
} Type guard
import { ALLOWED_SDK_FUNCTIONS, AUTO_RENAMEABLE_SDK_FUNCTIONS } from '@n8n/workflow-sdk/ast-interpreter/validators';
function isHardReservedName(name: string): boolean {
return ALLOWED_SDK_FUNCTIONS.has(name) && !AUTO_RENAMEABLE_SDK_FUNCTIONS.has(name);
} Try / catch
import { parseWorkflowCode } from '@n8n/workflow-sdk/codegen/parse-workflow-code';
try {
parseWorkflowCode(code);
} catch (e) {
if (e instanceof SyntaxError && /reserved SDK function name/.test(e.message)) {
// instruct user to rename the colliding local variable
}
throw e;
} Prevention
- Never name a local variable `node`, `workflow`, `trigger`, `sticky`, `placeholder`, `ifElse`, `switchCase`, `merge`, `splitInBatches`, `nextBatch`, or `newCredential`.
- Prefix local vars (my*, cfg*) to avoid collisions with SDK DSL keywords.
- Keep ALLOWED_SDK_FUNCTIONS minus AUTO_RENAMEABLE_SDK_FUNCTIONS visible as the hard-reserved list.
When it happens
Trigger: Declaring a const/variable with the same name as a reserved SDK function — e.g., `const node = 'foo'`, `const workflow = 123`, `const trigger = {}` — where the name is in the reserved set and not in AUTO_RENAMEABLE_SDK_FUNCTIONS (only subnode builder names like languageModel/memory/tool are auto-renamed).
Common situations: Using `node` as a variable name (very common — 'node' is a natural identifier); naming a variable `workflow` or `trigger`; refactoring that introduces a name collision with core SDK builders.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse workflow code: ${error.message}. This code c
- Failed to parse workflow code: ${error.message}. Common caus
- Code must export a workflow built with the workflow() SDK fu
- 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/4c570e4b852454af.
Report an issue: GitHub.