{"record":{"id":"6708591e8ede0821","repo":"n8n-io/n8n","slug":"the-response-type-must-be-a-string-received-ty","errorCode":null,"errorMessage":"The response type must be a string. Received: ${typeof response}","messagePattern":"The response type must be a string\\. Received: (.+?)","errorType":"exception","errorClass":"NodeOperationError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts","lineNumber":311,"sourceCode":"\tconst onlyContent = ctx.getNodeParameter('onlyContent', itemIndex, false) as boolean;\n\tlet elementsToOmit: string[] = [];\n\n\tif (onlyContent) {\n\t\tconst elementsToOmitUi = ctx.getNodeParameter('elementsToOmit', itemIndex, '') as\n\t\t\t| string\n\t\t\t| string[];\n\n\t\tif (typeof elementsToOmitUi === 'string') {\n\t\t\telementsToOmit = elementsToOmitUi\n\t\t\t\t.split(',')\n\t\t\t\t.filter((s) => s)\n\t\t\t\t.map((s) => s.trim());\n\t\t}\n\t}\n\n\treturn <T>(response: T) => {\n\t\tif (typeof response !== 'string') {\n\t\t\tthrow new NodeOperationError(\n\t\t\t\tctx.getNode(),\n\t\t\t\t`The response type must be a string. Received: ${typeof response}`,\n\t\t\t\t{ itemIndex },\n\t\t\t);\n\t\t}\n\t\tconst returnData: string[] = [];\n\n\t\tconst html = cheerio.load(response);\n\t\tconst htmlElements = html(cssSelector);\n\n\t\thtmlElements.each((_, el) => {\n\t\t\tlet value = html(el).html() || '';\n\n\t\t\tif (onlyContent) {\n\t\t\t\tlet htmlToTextOptions;\n\n\t\t\t\tif (elementsToOmit?.length) {\n\t\t\t\t\thtmlToTextOptions = {","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts#L293-L329","documentation":"Thrown by htmlOptimizer inside the AI HTTP Request tool. When 'Optimize Response' is on and 'Response Type' is 'html', the optimizer uses cheerio to parse the body, which requires a string. If the HTTP layer returned a non-string body (object, Buffer, number), this guard fires before cheerio runs.","triggerScenarios":"Selecting HTML response optimization against an API that returns JSON (parsed into an object) or binary data; setting responseType:'html' while the request option 'Response Format' causes the client to return a parsed object.","commonSituations":"Mismatch between the API's actual content type and the configured Response Type; a server unexpectedly returning JSON on an endpoint the user assumed was HTML; binary downloads routed through the HTML optimizer.","solutions":["Switch 'Response Type' to match the real body — 'json' for JSON APIs, 'text' for plain text.","Turn off 'Optimize Response' so the default optimizer stringifies non-string bodies.","Confirm the request actually returns HTML (check with a raw HTTP call) and fix the upstream URL/endpoint."],"exampleFix":"// before: optimizer set to html but API returns JSON\nresponseType: 'html'\n\n// after:\nresponseType: 'json'","handlingStrategy":"type-guard","validationCode":"const body = fullResponse.body ?? fullResponse;\nif (typeof body !== 'string' && responseType === 'html') {\n  // coerce or switch optimizer before calling htmlOptimizer\n  body = typeof body === 'object' ? JSON.stringify(body) : String(body);\n}","typeGuard":"const isStringBody = (b: unknown): b is string => typeof b === 'string';","tryCatchPattern":"try { return htmlOptimizer(ctx, itemIndex, maxLength)(body); }\ncatch (e) { if (e instanceof NodeOperationError) return defaultOptimizer(body); throw e; }","preventionTips":["Match the 'Response Type' to the API's real content type before enabling optimization.","Pre-check the response Content-Type header and pick the optimizer programmatically.","Disable 'Optimize Response' for endpoints with unpredictable body types."],"tags":["http-request-tool","response-optimization","type-mismatch","ai-tool"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}