{"record":{"id":"b73f6e5259defe87","repo":"n8n-io/n8n","slug":"sdk-forbidden-construct","errorCode":"SDK_FORBIDDEN_CONSTRUCT","errorMessage":"Arrow functions are not allowed. Use fromAi() directly instead of ($) => $.fromAi()","messagePattern":"Arrow functions are not allowed\\. Use fromAi\\(\\) directly instead of \\(\\$\\) => \\$\\.fromAi\\(\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/@n8n/workflow-sdk/src/lint/sdk/workflow-sdk-lint.ts","lineNumber":217,"sourceCode":"\t\t\t\t\t...locationOf(stmt),\n\t\t\t\t\tlintTarget: 'sdk',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tconst branchCounts = new Map<string, { count: number; line?: number; column?: number }>();\n\n\twalkAst(\n\t\tast,\n\t\t(node, parent) => {\n\t\t\tif (node.type === 'ImportDeclaration') return;\n\n\t\t\tconst forbidden = FORBIDDEN_NODE_TYPES[node.type];\n\t\t\tif (forbidden) {\n\t\t\t\tissues.push(\n\t\t\t\t\tlintIssue({\n\t\t\t\t\t\tcode: 'SDK_FORBIDDEN_CONSTRUCT',\n\t\t\t\t\t\tmessage: forbidden,\n\t\t\t\t\t\t...locationOf(node),\n\t\t\t\t\t\tlintTarget: 'sdk',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (node.type === 'Identifier' && DANGEROUS_GLOBALS.has(node.name)) {\n\t\t\t\tconst isPropertyName =\n\t\t\t\t\tparent?.type === 'MemberExpression' && parent.property === node && !parent.computed;\n\t\t\t\tconst isObjectKey = parent?.type === 'Property' && parent.key === node;\n\t\t\t\t// Mirrors the interpreter: safe global methods (e.g. JSON.stringify) are allowed.\n\t\t\t\tconst isSafeMethodObject =\n\t\t\t\t\tparent?.type === 'MemberExpression' &&\n\t\t\t\t\tparent.object === node &&\n\t\t\t\t\t!parent.computed &&\n\t\t\t\t\tparent.property.type === 'Identifier' &&\n\t\t\t\t\tgetSafeJSONMethod(node.name, parent.property.name) !== undefined;","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/lint/sdk/workflow-sdk-lint.ts#L199-L235","documentation":"SDK_FORBIDDEN_CONSTRUCT for ArrowFunctionExpression is a lint issue. The FORBIDDEN_NODE_TYPES map assigns arrow functions the message 'Use fromAi() directly instead of ($) => $.fromAi()'. The SDK builder interpreter rejects arrow functions entirely; fromAi() must be called directly as a parameter value.","triggerScenarios":"fromAi: ($) => $.fromAi('x'), callbacks like .map((x) => x), or any () => ... / (x) => ... expression in SDK builder code.","commonSituations":"Agent wraps fromAi in an arrow callback; developer uses functional array methods; LLM emits a lambda for a helper.","solutions":["Use fromAi() directly as the parameter value, e.g. fromAi: fromAi('x').","Replace array callbacks with declarative builder calls or move the logic to a Code node.","Inline any lambda logic so the SDK source has no arrow expressions."],"exampleFix":"// before\nexport default workflow().addNode(httpRequest({\n  parameters: { prompt: ($) => $.fromAi('prompt') },\n}));\n// after\nexport default workflow().addNode(httpRequest({\n  parameters: { prompt: fromAi('prompt') },\n}));","handlingStrategy":"validation","validationCode":"import { lintWorkflowSource } from '@n8n/workflow-sdk/lint/lint-workflow-source';\nconst issues = lintWorkflowSource(sdkSource);\nif (issues.some((i) => i.code === 'SDK_FORBIDDEN_CONSTRUCT' && i.message.includes('Arrow functions'))) {\n  throw new Error('Arrow functions are forbidden in SDK code; call fromAi() directly.');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use fromAi() directly as the parameter value, never ($) => $.fromAi().","Avoid array callbacks (.map(x => ...)) in SDK source — move transforms to a Code node.","Lint generated SDK code to catch arrow functions."],"tags":["lint","sdk","builder"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}