{"record":{"id":"6fbc4932c884b235","repo":"n8n-io/n8n","slug":"unable-to-parse-function-body","errorCode":null,"errorMessage":"Unable to parse function body","messagePattern":"Unable to parse function body","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/utils/code-helpers.ts","lineNumber":48,"sourceCode":"\n\t\treturn body;\n\t}\n\n\t// Handle regular functions: function(ctx) { ... }\n\tconst funcMatch = fnStr.match(/function\\s*\\(\\s*(\\w+)\\s*\\)\\s*\\{([\\s\\S]*)\\}$/);\n\tif (funcMatch) {\n\t\tconst paramName = funcMatch[1];\n\t\tlet body = funcMatch[2].trim();\n\n\t\t// Replace parameter name\n\t\tbody = body.replace(new RegExp(`${paramName}\\\\.\\\\$`, 'g'), '$');\n\t\tbody = body.replace(new RegExp(`${paramName}\\\\(`, 'g'), '$(');\n\t\tbody = body.replace(new RegExp(`${paramName}\\\\.`, 'g'), '');\n\n\t\treturn body;\n\t}\n\n\tthrow new Error('Unable to parse function body');\n}\n\n/**\n * Create a code helper for executing once with access to all items\n *\n * The function receives a context object with:\n * - ctx.$input.all() - get all input items\n * - ctx.$input.first() - get first input item\n * - ctx.$input.last() - get last input item\n * - ctx.$input.itemMatching(i) - get item at index\n * - ctx.$env, ctx.$vars, ctx.$secrets - environment access\n * - ctx.$now, ctx.$today - date helpers\n * - ctx.$execution, ctx.$workflow - metadata\n * - ctx('NodeName') - reference other node outputs\n *\n * @param fn - Function that processes all items and returns an array\n * @returns Code configuration for the Code node\n *","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/utils/code-helpers.ts#L30-L66","documentation":"Thrown by extractFunctionBody in code-helpers.ts when Function.prototype.toString() of the supplied callback matches neither the arrow-function regex nor the `function(ctx)` regex. The helpers runOnceForAllItems / runOnceForEachItem convert a TS closure into a Code-node source string by stringifying the function and rewriting the ctx. parameter; anything that diverges from the two supported shapes cannot be transformed.","triggerScenarios":"Passing a generator function (function*), an async function whose stringified form carries modifiers the regex skips, a bound function (.bind()), a method reference, or a zero-argument function. Minified/transpiled builds that mangle fn.toString() also fail the match.","commonSituations":"Production bundlers rename or inline functions so fn.toString() no longer matches `(ctx) => ...`; developer passes a class method `this.handler.bind(this)`; using an async generator for streaming-style code.","solutions":["Pass an arrow function (ctx) => { ... } or a named function(ctx) { ... } with exactly one parameter.","Avoid .bind() — capture closure variables directly inside the arrow body.","In bundler setups, mark the callback as non-mangled (function names preserved) or inline the source string."],"exampleFix":"// before\nrunOnceForAllItems(this.processItems.bind(this));\n// after\nrunOnceForAllItems((ctx) => {\n  const items = ctx.$input.all();\n  return [{ json: { sum: items.length } }];\n});","handlingStrategy":"validation","validationCode":"function isSupportedCodeHelperFn(fn: unknown): boolean {\n  if (typeof fn !== 'function') return false;\n  const s = fn.toString();\n  return /^\\s*\\(?\\w+\\)?\\s*=>\\s+.+$/s.test(s) || /function\\s*\\(\\s*\\w+\\s*\\)\\s*\\{[\\s\\S]*\\}$/.test(s);\n}\n\nif (!isSupportedCodeHelperFn(cb)) {\n  throw new Error('Pass an arrow (ctx) => {...} or function(ctx) {...} with one parameter');\n}","typeGuard":"function isArrowOrNamedFunction(ctx: unknown, fn: unknown): fn is (ctx: any) => any {\n  if (typeof fn !== 'function') return false;\n  const s = fn.toString();\n  return /^\\s*\\(?\\w+\\)?\\s*=>/.test(s) || /^\\s*function\\s*\\(\\s*\\w+\\s*\\)/.test(s);\n}","tryCatchPattern":"try {\n  runOnceForAllItems(cb as (ctx: AllItemsContext) => any);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Unable to parse function body') {\n    throw new Error('Code helper could not stringify the callback; pass an un-bound arrow or function(ctx).');\n  }\n  throw e;\n}","preventionTips":["Always pass an inline arrow (ctx) => { ... } to runOnceForAllItems / runOnceForEachItem.","Never pass a .bind() result or a method reference.","Configure your bundler to preserve function names/source for files containing code helpers."],"tags":["runtime","code-helpers","function-parsing"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}