{"record":{"id":"5cc1726848472124","repo":"Significant-Gravitas/AutoGPT","slug":"unexpected-n8n-api-response-format","errorCode":null,"errorMessage":"Unexpected n8n API response format","messagePattern":"Unexpected n8n API response format","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"autogpt_platform/frontend/src/app/(platform)/library/components/LibraryImportDialog/components/ExternalWorkflowTab/fetchWorkflowFromUrl.ts","lineNumber":82,"sourceCode":"  const safeId = parseInt(templateId, 10);\n  if (!Number.isFinite(safeId) || safeId <= 0) {\n    throw new Error(\"Invalid template ID\");\n  }\n  const res = await fetch(`${N8N_TEMPLATES_API}/${safeId.toString()}`);\n  if (!res.ok) throw new Error(`n8n template not found (${res.status})`);\n\n  const contentLength = res.headers.get(\"content-length\");\n  if (contentLength && parseInt(contentLength, 10) > MAX_RESPONSE_BYTES) {\n    throw new Error(\"Response too large.\");\n  }\n\n  const text = await res.text();\n  if (text.length > MAX_RESPONSE_BYTES) throw new Error(\"Response too large.\");\n\n  const data = JSON.parse(text);\n  const template = data?.workflow ?? data;\n  const workflow = template?.workflow ?? template;\n  if (!workflow?.nodes) throw new Error(\"Unexpected n8n API response format\");\n  if (!workflow.name) workflow.name = template?.name ?? data?.name ?? \"\";\n  return JSON.stringify(workflow);\n}\n","sourceCodeStart":64,"sourceCodeEnd":86,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryImportDialog/components/ExternalWorkflowTab/fetchWorkflowFromUrl.ts#L64-L86","documentation":"Thrown by fetchN8nWorkflow after JSON.parse succeeds but the unwrapped object has no `nodes` array. The code tries several envelope shapes (data.workflow, data itself, template.workflow, template) because the n8n templates API has changed its response shape over time; if none of them yield a workflow with a `nodes` array, the response is considered unparseable. A JSON.parse failure would throw a SyntaxError instead — this error specifically means valid JSON, unexpected shape.","triggerScenarios":"n8n API returns a redirect/HTML-wrapped payload (proxy interference), an error envelope like {code:..., message:...} with 200 status, or a new API version that nests the workflow differently than the tried paths.","commonSituations":"n8n ships an API change moving/renaming the workflow field; an intermediary (corporate proxy, CDN) rewriting the response; requesting a non-workflow resource ID that returns metadata-only JSON with 200.","solutions":["Log/inspect the actual JSON returned by the N8N_TEMPLATES_API URL in DevTools to see the new envelope shape.","If the shape changed upstream, extend the unwrap chain in fetchN8nWorkflow (add the new path) — this is exactly why the chain exists.","Verify the pasted ID is a workflow template, not a collection/credential ID.","Retry later / bypass proxies if the payload was rewritten in transit."],"exampleFix":"// before\nconst template = data?.workflow ?? data;\nconst workflow = template?.workflow ?? template;\n\n// after (extend envelope chain after confirming new shape)\nconst template = data?.workflow ?? data?.data ?? data;\nconst workflow = template?.workflow ?? template;","handlingStrategy":"try-catch","validationCode":"function hasNodes(workflow: unknown): workflow is { nodes: unknown[]; name?: string } {\n  return (\n    typeof workflow === \"object\" && workflow !== null &&\n    Array.isArray((workflow as any).nodes)\n  );\n}","typeGuard":"function isN8nWorkflow(data: unknown): data is { nodes: unknown[]; name?: string } {\n  return hasNodes(data) || hasNodes((data as any)?.workflow);\n}","tryCatchPattern":"try {\n  const wf = await fetchN8nWorkflow(id);\n} catch (error) {\n  if (error instanceof Error && error.message === \"Unexpected n8n API response format\") {\n    // upstream shape changed — inspect the raw response and extend the unwrap chain\n  }\n}","preventionTips":["Type-guard the unwrapped object (nodes is an array) before trusting it, as shown.","Keep the envelope-unwrap chain in one place so an upstream shape change is a one-line fix.","Separate JSON-parse failures (SyntaxError) from shape failures in error handling — they mean different things."],"tags":["n8n","import","response-shape","third-party-api","frontend"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}