{"record":{"id":"d824faad96b846f2","repo":"n8n-io/n8n","slug":"toolname-requires-resumesubagent-and-cancelsuba","errorCode":null,"errorMessage":"${toolName} requires resumeSubAgent and cancelSubAgent to be configured together","messagePattern":"(.+?) requires resumeSubAgent and cancelSubAgent to be configured together","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/runtime/tools/delegate-sub-agent-tool.ts","lineNumber":459,"sourceCode":" *   agent.tool(createDelegateSubAgentTool({\n *     runSubAgent: (request) => runner.run(request),\n *     availableSubAgents,\n *     policy: { maxChildren: 10 },\n *   }));\n */\nexport function createDelegateSubAgentTool(options: CreateDelegateSubAgentToolOptions = {}) {\n\t// Per-parent child path index for stable task paths (/root/name_0, /root/name_1, ...).\n\tconst childPathIndexes = new Map<string, number>();\n\tconst toolName = resolveDelegateSubAgentToolName(options.name);\n\tconst resolvedOptions: CreateDelegateSubAgentToolOptions = {\n\t\t...options,\n\t\tpolicy: resolveDelegateSubAgentPolicy(options.policy, toolName),\n\t};\n\tif (\n\t\t(resolvedOptions.resumeSubAgent === undefined) !==\n\t\t(resolvedOptions.cancelSubAgent === undefined)\n\t) {\n\t\tthrow new Error(\n\t\t\t`${toolName} requires resumeSubAgent and cancelSubAgent to be configured together`,\n\t\t);\n\t}\n\tconst inlineProviderToolInstruction = resolvedOptions.resolveInlineSubAgentProviderTools\n\t\t? \"Provider-defined tools are loaded for the inline child's selected model provider.\"\n\t\t: 'Inline children do not inherit provider-defined tools.';\n\n\tconst toolBuilder = new Tool(toolName)\n\t\t.description(resolveDelegateSubAgentDescription(resolvedOptions))\n\t\t.systemInstruction(\n\t\t\tresolveDelegateSubAgentSystemInstruction(\n\t\t\t\tresolvedOptions,\n\t\t\t\ttoolName,\n\t\t\t\tinlineProviderToolInstruction,\n\t\t\t),\n\t\t)\n\t\t.input(delegateSubAgentInputSchema)\n\t\t.output(delegateSubAgentOutputSchema);","sourceCodeStart":441,"sourceCodeEnd":477,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/runtime/tools/delegate-sub-agent-tool.ts#L441-L477","documentation":"Thrown during createDelegateSubAgentTool when exactly one of resumeSubAgent and cancelSubAgent is provided. The library requires these two callbacks to be configured as a pair because resumption and cancellation are the two lifecycle exits for a suspended child agent — providing one without the other leaves the delegation in a half-configured state that would fail at runtime.","triggerScenarios":"Calling createDelegateSubAgentTool({ resumeSubAgent: fn }) without cancelSubAgent, or vice versa. The XOR check (one is undefined, the other is not) is what trips the error.","commonSituations":"Intending to support suspend/resume of delegated children but forgetting the cancellation handler. Copying a partial configuration from example code that only showed resume. Upgrading from a version where these were independent options to one where they must be paired.","solutions":["Provide both resumeSubAgent and cancelSubAgent callbacks together.","If you do not need suspend/resume support, omit both callbacks entirely.","If you only need resume, implement a no-op cancelSubAgent that calls the host's cancellation API."],"exampleFix":"// before\nconst tool = createDelegateSubAgentTool({\n  resumeSubAgent: (req, helpers) => host.resume(req),\n});\n// after\nconst tool = createDelegateSubAgentTool({\n  resumeSubAgent: (req, helpers) => host.resume(req),\n  cancelSubAgent: (req, ctx) => host.cancel(req),\n});","handlingStrategy":"validation","validationCode":"function validateDelegateCallbacks(opts: CreateDelegateSubAgentToolOptions): void {\n  const hasResume = opts.resumeSubAgent !== undefined;\n  const hasCancel = opts.cancelSubAgent !== undefined;\n  if (hasResume !== hasCancel) {\n    throw new Error('resumeSubAgent and cancelSubAgent must both be provided or both omitted');\n  }\n}\nvalidateDelegateCallbacks(options);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always provide resumeSubAgent and cancelSubAgent as a pair, or omit both.","Create a factory helper that takes both callbacks or neither to enforce pairing at the type level.","Document in your team's code review checklist that these two options are coupled."],"tags":["configuration","delegate-tool","lifecycle","validation"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}