{"record":{"id":"90649245153b5b31","repo":"n8n-io/n8n","slug":"unsupported-syntax-nodetype-is-not-allowed-i","errorCode":null,"errorMessage":"Unsupported syntax: '${nodeType}' is not allowed in SDK code","messagePattern":"Unsupported syntax: '(.+?)' is not allowed in SDK code","errorType":"exception","errorClass":"UnsupportedNodeError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts","lineNumber":83,"sourceCode":"\t * Interpret the AST program and return the result.\n\t */\n\tinterpret(ast: ESTree.Program): unknown {\n\t\tlet result: unknown;\n\n\t\tfor (const stmt of ast.body) {\n\t\t\tvalidateNodeType(stmt, this.sourceCode);\n\n\t\t\tswitch (stmt.type) {\n\t\t\t\tcase 'VariableDeclaration':\n\t\t\t\t\tthis.visitVariableDeclaration(stmt);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'ExpressionStatement':\n\t\t\t\t\tresult = this.evaluate(stmt.expression);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'ExportDefaultDeclaration':\n\t\t\t\t\treturn this.evaluate(stmt.declaration as ESTree.Expression);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new UnsupportedNodeError(stmt.type, stmt.loc ?? undefined, this.sourceCode);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Process a variable declaration.\n\t */\n\tprivate visitVariableDeclaration(node: ESTree.VariableDeclaration): void {\n\t\t// Only allow const declarations\n\t\tif (node.kind !== 'const') {\n\t\t\tthrow new SecurityError(\n\t\t\t\tnode.kind,\n\t\t\t\tnode.loc ?? undefined,\n\t\t\t\tthis.sourceCode,\n\t\t\t\t`'${node.kind}' declarations are not allowed. Use 'const' only.`,\n\t\t\t);","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts#L65-L101","documentation":"Thrown as UnsupportedNodeError (extends InterpreterError) by the SDK AST interpreter when a top-level statement is not VariableDeclaration, ExpressionStatement, or ExportDefaultDeclaration. The message lists the offending node type and, when source location is present, appends a code frame. This is a sandbox guard: only a restricted subset of JS is evaluable as SDK code.","triggerScenarios":"Authoring SDK code with a FunctionDeclaration, IfStatement, ForStatement, ReturnStatement at top level, a class declaration, or any other statement kind outside the allowed three. Also triggered by code that the parser accepts but the interpreter refuses (e.g. a try/catch block, a switch).","commonSituations":"Users pasting ordinary JS into an SDK code box expecting general execution; tooling that emits scaffolding (imports, functions) around the SDK snippet; attempting control flow or function definitions that the SDK vocabulary disallows.","solutions":["Restructure SDK code to use only const declarations, expression statements, and an optional export default.","Move logic into allowed SDK function calls instead of defining helper functions at top level.","Replace control-flow statements with expressions (e.g. ternaries, allowed SDK helpers)."],"exampleFix":"// before\nfunction transform(x) { return x.toUpperCase(); }\nexport default transform(input);\n// after\nconst transform = (x) => x.toUpperCase();\nexport default transform(input);","handlingStrategy":"validation","validationCode":"import { parseSDKCode } from '@n8n/workflow-sdk';\nimport { UnsupportedNodeError } from '@n8n/workflow-sdk';\n\nfunction preflightSDKCode(code: string): void {\n  const ast = parseSDKCode(code); // throws on parse errors\n  const allowed = new Set(['VariableDeclaration', 'ExpressionStatement', 'ExportDefaultDeclaration']);\n  for (const stmt of ast.body) {\n    if (!allowed.has(stmt.type)) {\n      throw new Error(`SDK code may not contain '${stmt.type}'. Use only const declarations, expression statements, and an optional export default.`);\n    }\n  }\n}","typeGuard":"import type { Program, Statement } from 'estree';\n\nconst ALLOWED_SDK_STATEMENTS = new Set<Statement['type']>([\n  'VariableDeclaration',\n  'ExpressionStatement',\n  'ExportDefaultDeclaration',\n]);\n\nfunction isAllowedSdkStatement(stmt: Statement): boolean {\n  return ALLOWED_SDK_STATEMENTS.has(stmt.type);\n}","tryCatchPattern":"try {\n  return interpret(code, sdkFunctions);\n} catch (e) {\n  if (e?.name === 'UnsupportedNodeError') {\n    return { error: 'This SDK code uses unsupported syntax.', detail: e.message };\n  }\n  throw e;\n}","preventionTips":["Restrict SDK code to const declarations, expression statements, and one export default.","Validate the AST before evaluation when accepting user-authored SDK code.","Surface UnsupportedNodeError messages with their code frame to help authors fix the syntax."],"tags":["workflow-sdk","ast-interpreter","validation","sandbox","security"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}