{"record":{"id":"2b006431821d9727","repo":"n8n-io/n8n","slug":"unsupported-syntax-destructuring-in-variable-dec","errorCode":null,"errorMessage":"Unsupported syntax: 'Destructuring in variable declaration' is not allowed in SDK code","messagePattern":"Unsupported syntax: 'Destructuring in variable declaration' 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":106,"sourceCode":"\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);\n\t\t}\n\n\t\tfor (const declarator of node.declarations) {\n\t\t\tif (declarator.id.type !== 'Identifier') {\n\t\t\t\tthrow new UnsupportedNodeError(\n\t\t\t\t\t'Destructuring in variable declaration',\n\t\t\t\t\tdeclarator.loc ?? undefined,\n\t\t\t\t\tthis.sourceCode,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst name = declarator.id.name;\n\n\t\t\t// Check for SDK function name collisions\n\t\t\tif (isAllowedSDKFunction(name)) {\n\t\t\t\tif (isAutoRenameableSDKFunction(name)) {\n\t\t\t\t\t// Auto-rename subnode variables that collide with SDK function names\n\t\t\t\t\tconst safeName = this.generateSafeName(name);\n\t\t\t\t\tconst value = declarator.init ? this.evaluate(declarator.init) : undefined;\n\t\t\t\t\tthis.renamedVariables.set(name, safeName);\n\t\t\t\t\tthis.variables.set(safeName, value);\n\t\t\t\t\tcontinue;\n\t\t\t\t}","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts#L88-L124","documentation":"The SDK interpreter only supports simple `const name = value` declarations with a single identifier name. Destructuring patterns (`const { a, b } = obj` or `const [x, y] = arr`) are rejected because the interpreter stores variables in a flat `Map<string, unknown>` keyed by one identifier per declarator. This restriction keeps the sandboxed evaluation model simple and predictable — the interpreter never has to pattern-match or bind multiple names from one initializer.","triggerScenarios":"Writing `const { name, type } = node.parameters` or `const [first, second] = items` in SDK code passed to `interpretSDKCode()`. The parser accepts the syntax (valid JS), but `visitVariableDeclaration` at interpreter.ts:105 checks `declarator.id.type !== 'Identifier'` and throws when the id is an `ObjectPattern` or `ArrayPattern`.","commonSituations":"Porting JS/TS snippets that rely on destructuring into SDK builder code; extracting fields from an SDK function's return value; unpacking AI subnode parameters; refactoring from Code-node-style JS where destructuring is idiomatic.","solutions":["Replace destructuring with one `const` per field: `const name = obj.name; const type = obj.type;`","Access properties inline where needed instead of binding them first","Move complex unpacking into a Code node and pass the result forward"],"exampleFix":"// before\nconst { name, typeVersion } = node.parameters;\n\n// after\nconst name = node.parameters.name;\nconst typeVersion = node.parameters.typeVersion;","handlingStrategy":"validation","validationCode":"// Pre-check SDK code for destructuring before interpreting\nimport { parse } from 'acorn';\n\nfunction hasDestructuring(code: string): boolean {\n  const ast = parse(code, { ecmaVersion: 'latest', sourceType: 'module' });\n  let found = false;\n  walk(ast, (node) => {\n    if (\n      node.type === 'VariableDeclarator' &&\n      (node.id.type === 'ObjectPattern' || node.id.type === 'ArrayPattern')\n    ) {\n      found = true;\n    }\n  });\n  return found;\n}\n\nif (hasDestructuring(sdkCode)) {\n  // reject before calling interpretSDKCode\n}","typeGuard":null,"tryCatchPattern":"import { UnsupportedNodeError } from '@n8n/workflow-sdk/ast-interpreter/errors';\n\ntry {\n  interpretSDKCode(sdkCode, sdkFunctions);\n} catch (e) {\n  if (e instanceof UnsupportedNodeError && e.message.includes('Destructuring')) {\n    // prompt user to rewrite as separate const declarations\n  }\n  throw e;\n}","preventionTips":["Always declare one variable per `const` statement","Avoid destructuring syntax entirely in SDK builder code","Lint SDK code with a custom rule that rejects ObjectPattern/ArrayPattern in VariableDeclarator"],"tags":["sdk-interpreter","destructuring","variable-declaration"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}