{"record":{"id":"381a63d2ce627ec4","repo":"n8n-io/n8n","slug":"tool-toolcall-toolname-not-found","errorCode":null,"errorMessage":"Tool ${toolCall.toolName} not found","messagePattern":"Tool (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/runtime/loop/agent-runtime.ts","lineNumber":377,"sourceCode":"\t\tif (!state) {\n\t\t\tthrow new StaleResumeError(`No suspended run found for runId: ${this.runId}`);\n\t\t}\n\n\t\tconst toolCall = state.pendingToolCalls[options.toolCallId];\n\t\tif (!toolCall) {\n\t\t\tthrow new StaleResumeError(`No tool call found for toolCallId: ${options.toolCallId}`);\n\t\t}\n\n\t\tconst list = AgentMessageList.deserialize(state.messageList);\n\t\tthis.context.hydrateDeferredToolsFromList(list);\n\t\tawait hydrateFileParts(list.messages(), this.config.fileStore, {\n\t\t\tthreadId: state.persistence?.threadId,\n\t\t});\n\n\t\tconst tool = this.context\n\t\t\t.getCurrentTools(state.persistence)\n\t\t\t.find((t) => t.name === toolCall.toolName);\n\t\tif (!tool) throw new Error(`Tool ${toolCall.toolName} not found`);\n\n\t\tlet resumeData: unknown = data;\n\t\tlet abortScope: AgentAbortScope | undefined;\n\n\t\tconst resumeSchema = toolCall.suspended ? toolCall.resumeSchema : tool.resumeSchema;\n\t\tif (!isCancellation(resumeData) && resumeSchema) {\n\t\t\tconst parseResult = await parseWithSchema(resumeSchema, data, { stripUnknown: true });\n\t\t\tif (!parseResult.success) {\n\t\t\t\tthrow new Error(`Invalid resume payload: ${parseResult.error}`);\n\t\t\t}\n\t\t\tresumeData = parseResult.data as JSONValue;\n\t\t}\n\n\t\ttry {\n\t\t\t// Merge persisted execution options with fresh caller options\n\t\t\tconst {\n\t\t\t\trunId: _rid,\n\t\t\t\ttoolCallId: _tcid,","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/runtime/loop/agent-runtime.ts#L359-L395","documentation":"Thrown when a node is correctly configured for a raw XML/SOAP body (sendBody=true, contentType='raw', rawContentType matching an XML media type) but the body field itself is empty or not a string. Without a body the request would be sent empty, so the validator blocks it.","triggerScenarios":"params.sendBody === true AND params.contentType === 'raw' AND rawContentType matches the XML media pattern (text/xml, application/xml, application/...+xml) AND isMissingBody(params.body) — i.e. body is not a string or is whitespace-only.","commonSituations":"Configuring the raw content type but forgetting to fill body; referencing a field that resolves to empty at build time; an AI builder sets up the envelope scaffolding but leaves body blank.","solutions":["Put the XML envelope string (or an expression like expr('{{ $json.soapBody }}')) into the body field.","Confirm rawContentType stays an XML media type and contentType stays 'raw'.","Remove any specifyBody/jsonBody/bodyParameters so only the raw body is used."],"exampleFix":"// before\nhttpRequest({\n  name: 'SOAP Call',\n  sendBody: true,\n  contentType: 'raw',\n  rawContentType: 'text/xml',\n  body: '',\n});\n\n// after\nhttpRequest({\n  name: 'SOAP Call',\n  sendBody: true,\n  contentType: 'raw',\n  rawContentType: 'text/xml',\n  body: expr('{{ $json.soapEnvelope }}'),\n});","handlingStrategy":"validation","validationCode":"const XML_MEDIA = /\\b(?:text|application)\\/(?:[\\w.+-]*\\+)?xml\\b/i;\n\nfunction isMissingBody(value: unknown): boolean {\n  return typeof value !== 'string' || value.trim() === '';\n}\n\n// before building:\nif (params.sendBody === true && params.contentType === 'raw' && XML_MEDIA.test(String(params.rawContentType ?? '')) && isMissingBody(params.body)) {\n  throw new Error('Raw XML body configured but body is empty; set body to the envelope or an expression.');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair a rawContentType with a non-empty body field.","Use an expression (expr('={{ $json.soapBody }}')) when the envelope comes from upstream data.","Unit-test SOAP nodes with a sample envelope to catch empty-body regressions."],"tags":["http-request","xml","soap","body"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}