{"record":{"id":"321083b06c243c4e","repo":"n8n-io/n8n","slug":"cannot-assign-property-on-string-obj","errorCode":null,"errorMessage":"Cannot assign property on ${String(obj)}","messagePattern":"Cannot assign property on (.+?)","errorType":"exception","errorClass":"InterpreterError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts","lineNumber":726,"sourceCode":"\t\t\t\tnode.loc ?? undefined,\n\t\t\t\tthis.sourceCode,\n\t\t\t);\n\t\t}\n\n\t\tvalidateMemberExpression(node.left, this.sourceCode);\n\n\t\tif (node.left.object.type === 'Super') {\n\t\t\tthrow new UnsupportedNodeError(\n\t\t\t\t'super keyword is not supported in SDK code',\n\t\t\t\tnode.left.object.loc ?? undefined,\n\t\t\t\tthis.sourceCode,\n\t\t\t);\n\t\t}\n\n\t\tconst obj = this.evaluate(node.left.object);\n\n\t\tif (obj === null || obj === undefined) {\n\t\t\tthrow new InterpreterError(\n\t\t\t\t`Cannot assign property on ${String(obj)}`,\n\t\t\t\tnode.loc ?? undefined,\n\t\t\t\tthis.sourceCode,\n\t\t\t);\n\t\t}\n\n\t\tlet propName: string | number;\n\t\tif (node.left.property.type === 'Identifier' && !node.left.computed) {\n\t\t\tpropName = node.left.property.name;\n\t\t} else if (node.left.property.type === 'Literal') {\n\t\t\tpropName = node.left.property.value as string | number;\n\t\t} else {\n\t\t\tthrow new UnsupportedNodeError(\n\t\t\t\t'Dynamic property assignment',\n\t\t\t\tnode.left.property.loc ?? undefined,\n\t\t\t\tthis.sourceCode,\n\t\t\t);\n\t\t}","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts#L708-L744","documentation":"Thrown by visitAssignmentExpression after evaluating `node.left.object` to a value that is null or undefined. The interpreter then refuses to set a property on it (would be a TypeError at runtime). This is a runtime evaluation error inside the safe interpreter, not a static syntax rejection.","triggerScenarios":"SDK code like `foo.bar = 1` where `foo` evaluates to null or undefined at interpretation time (e.g., `foo` was never declared/assigned, or was explicitly set to null). Also reachable if an SDK function returns undefined and you then assign a property on the result.","commonSituations":"Typo in a variable name; referencing a variable before its declaration line; chaining `.parameters()` on a node() call that returned undefined due to wrong usage; assigning onto the result of a function that doesn't return an object.","solutions":["Check that the object on the left side of the assignment is declared and non-null before the assignment line.","Replace `x.y = value` with construction via an object literal: `const x = { y: value };`.","If assigning onto an SDK builder result, verify the builder function (workflow/node/trigger) actually returns an object — don't reassign internal fields; use the builder's chained methods instead."],"exampleFix":"// before\nconst cfg = getMaybeUndef();\ncfg.timeout = 30;\n\n// after\nconst raw = getMaybeUndef();\nconst cfg = { ...raw, timeout: 30 };","handlingStrategy":"validation","validationCode":"// Static check: every assignment target's object must be a declared identifier or a call chain\nimport { parseSDKCode } from '@n8n/workflow-sdk/ast-interpreter/parser';\n\nfunction findUnsafeAssignments(code: string, declared: Set<string>): string[] {\n  const issues: string[] = [];\n  const ast = parseSDKCode(code);\n  JSON.stringify(ast, (k, v) => {\n    if (v?.type === 'AssignmentExpression' && v.left?.type === 'MemberExpression') {\n      const obj = v.left.object;\n      if (obj.type === 'Identifier' && !declared.has(obj.name)) {\n        issues.push(`Possible null/undefined assignment target '${obj.name}' at line ${v.loc?.start.line}`);\n      }\n    }\n    return v;\n  });\n  return issues;\n}","typeGuard":"function isNonNullObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null;\n}","tryCatchPattern":"import { interpretSDKCode } from '@n8n/workflow-sdk/ast-interpreter/interpreter';\nimport { InterpreterError } from '@n8n/workflow-sdk/ast-interpreter/errors';\n\ntry {\n  interpretSDKCode(code, sdkFunctions);\n} catch (e) {\n  if (e instanceof InterpreterError && /Cannot assign property on/.test(e.message)) {\n    // Tell user to initialize the object before assigning a property onto it\n  }\n  throw e;\n}","preventionTips":["Always initialize objects with a literal (`const x = {}`) before assigning properties onto them.","Use object-literal construction (`const x = { y: 1 }`) rather than declare-then-mutate.","Track declared identifiers in a Set and statically verify assignment targets reference a declared name."],"tags":["sdk","ast-interpreter","null-reference","assignment"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}