{"record":{"id":"a41e64ae8cfc3780","repo":"n8n-io/n8n","slug":"named-object-syntax-does-not-support-ondone-b","errorCode":null,"errorMessage":"Named object syntax does not support .onDone() - branches are configured in the constructor","messagePattern":"Named object syntax does not support \\.onDone\\(\\) - branches are configured in the constructor","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/workflow-sdk/src/workflow-builder/control-flow-builders/split-in-batches.ts","lineNumber":550,"sourceCode":"\t\t\t// expressed in the connection target (e.g., each: sibNode or each: processNode.to(sibNode))\n\t\t\t// The workflow-builder's _hasLoop handling is only for the fluent API's .loop() method\n\t\t}\n\t}\n\n\t/**\n\t * Fluent API: Not supported for named syntax builder (use constructor branches instead)\n\t */\n\tonEachBatch(_target: BranchTarget): this {\n\t\tthrow new Error(\n\t\t\t'Named object syntax does not support .onEachBatch() - branches are configured in the constructor',\n\t\t);\n\t}\n\n\t/**\n\t * Fluent API: Not supported for named syntax builder (use constructor branches instead)\n\t */\n\tonDone(_target: BranchTarget): this {\n\t\tthrow new Error(\n\t\t\t'Named object syntax does not support .onDone() - branches are configured in the constructor',\n\t\t);\n\t}\n\n\tgetAllNodes(): Array<NodeInstance<string, string, unknown>> {\n\t\treturn [this.sibNode, ...this._doneNodes, ...this._eachNodes];\n\t}\n\n\tgetDoneNodes(): Array<NodeInstance<string, string, unknown>> {\n\t\treturn this._doneNodes;\n\t}\n\n\tgetEachNodes(): Array<NodeInstance<string, string, unknown>> {\n\t\treturn this._eachNodes;\n\t}\n\n\thasLoop(): boolean {\n\t\treturn this._hasLoop;","sourceCodeStart":532,"sourceCodeEnd":568,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/workflow-sdk/src/workflow-builder/control-flow-builders/split-in-batches.ts#L532-L568","documentation":"Thrown by NamedSplitInBatchesBuilderImpl.onDone(). Symmetric to onEachBatch: the named-object builder variant fixes the done branch in the constructor and does not accept the fluent .onDone() method, which would mutate the done target after construction.","triggerScenarios":"Constructing with named syntax and then calling .onDone(target) on the returned builder.","commonSituations":"Mixing styles; refactoring a fluent-style chain onto a named-syntax builder; appending a done handler after the fact.","solutions":["Provide the done branch in the constructor object: splitInBatches('sib', { each, done: endNode }).","Switch to the fluent builder variant if you need .onDone().","Decide on one style (named vs fluent) per SplitInBatches and stay with it."],"exampleFix":"// before\nconst sib = splitInBatches('sib', { each: processNode });\nsib.onDone(endNode); // throws\n// after\nconst sib = splitInBatches('sib', { each: processNode, done: endNode });","handlingStrategy":"type-guard","validationCode":"function isNamedSyntaxBuilder(b: unknown): boolean {\n  return b instanceof NamedSplitInBatchesBuilderImpl;\n}\n\nif (isNamedSyntaxBuilder(builder)) {\n  throw new Error('Use constructor branches { each, done }, not .onDone()');\n}","typeGuard":"function supportsFluentBranches(b: SplitInBatchesBuilder): boolean {\n  return !Object.is(b.onDone, NamedSplitInBatchesBuilderImpl.prototype.onDone);\n}","tryCatchPattern":"try {\n  builder.onDone(target);\n} catch (e) {\n  if (e instanceof Error && /Named object syntax does not support/.test(e.message)) {\n    // reconfigure via constructor branches instead\n  }\n  throw e;\n}","preventionTips":["When using named syntax, supply `done` in the constructor object.","Reserve .onDone() for the fluent builder variant.","Do not mix named-object construction with fluent branch methods."],"tags":["runtime","builder","split-in-batches","fluent-api"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}