{"record":{"id":"3ee331bfe682a10f","repo":"alibaba/page-agent","slug":"invalid-response","errorCode":"INVALID_RESPONSE","errorMessage":"Response body is not valid JSON","messagePattern":"Response body is not valid JSON","errorType":"exception","errorClass":"InvokeError","httpStatus":null,"severity":"error","filePath":"packages/llms/src/OpenAIClient.ts","lineNumber":135,"sourceCode":"\t\t\t\t\tInvokeErrorTypes.SERVER_ERROR,\n\t\t\t\t\t`Server error: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.UNKNOWN,\n\t\t\t\t`HTTP ${response.status}: ${errorMessage}`,\n\t\t\t\terrorData\n\t\t\t)\n\t\t}\n\n\t\t// 4. Parse and validate response\n\t\tlet data: any\n\t\ttry {\n\t\t\tdata = await response.json()\n\t\t} catch (error) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tthrow new InvokeError(\n\t\t\t\tInvokeErrorTypes.INVALID_RESPONSE,\n\t\t\t\t'Response body is not valid JSON',\n\t\t\t\terror\n\t\t\t)\n\t\t}\n\n\t\tconst choice = data.choices?.[0]\n\t\tif (!choice) {\n\t\t\tthrow new InvokeError(InvokeErrorTypes.INVALID_SCHEMA, 'No choices in response', data)\n\t\t}\n\n\t\t// Check finish_reason\n\t\tswitch (choice.finish_reason) {\n\t\t\tcase 'tool_calls':\n\t\t\tcase 'function_call': // gemini\n\t\t\tcase 'stop': // some models use this even with tool calls\n\t\t\t\tbreak\n\t\t\tcase 'length':","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/alibaba/page-agent/blob/d02db1ee7c41f5315beda88bab2fe935c580f662/packages/llms/src/OpenAIClient.ts#L117-L153","documentation":"The HTTP request succeeded but response.json() failed — the response body is not valid JSON. This usually means the baseURL actually points at an HTML page, a proxy error page, or an empty/SSE stream rather than a JSON API. The parse error is attached as cause.","triggerScenarios":"invoke() where the server returns HTML (login page, 200-redirected captive portal, Cloudflare interstitial), plain text, or an empty body with 200; pointing baseURL at a UI page instead of the API path; a gateway returning a non-JSON maintenance page.","commonSituations":"baseURL pointed at the provider's website instead of the API endpoint; reverse proxy serving an HTML error/landing page with 200; streaming endpoints that return SSE when the client expects a single JSON body; server truncating the response.","solutions":["curl the exact URL with a sample body and inspect Content-Type and the raw response","Fix baseURL to the JSON chat/completions endpoint including the /v1 path","If the endpoint only supports streaming, ensure the request is configured so the server returns a single JSON object (no stream:true)","Check for proxies/CDNs injecting HTML pages"],"exampleFix":"// before\nnew OpenAIClient({ baseURL: 'https://openai.com' }) // returns HTML\n\n// after\nnew OpenAIClient({ baseURL: 'https://api.openai.com/v1' })","handlingStrategy":"type-guard","validationCode":"// confirm the endpoint returns JSON before wiring the client\nconst r = await fetch(cfg.baseURL + '/models', { headers: { Authorization: `Bearer ${cfg.apiKey}` } })\nconst ct = r.headers.get('content-type') ?? ''\nif (!ct.includes('application/json')) throw new Error(`Expected JSON, got ${ct}`)","typeGuard":"const isInvalidJsonError = (e: unknown): e is InvokeError =>\n  e instanceof InvokeError && e.code === 'INVALID_RESPONSE' && /not valid JSON/.test(e.message)","tryCatchPattern":"try {\n  await client.invoke(req)\n} catch (e) {\n  if (isInvalidJsonError(e)) throw new Error(`baseURL likely points at a non-API page: ${cfg.baseURL}`)\n  throw e\n}","preventionTips":["Validate baseURL against the documented API path, not the website URL","Beware CDNs/proxies serving HTML interstitials with 200","Avoid stream:true with this client — it expects a single JSON body"],"tags":["json","invalid-response","openai-client"],"backgroundTag":"invalid-json-response","analyzedSha":"d02db1ee7c41f5315beda88bab2fe935c580f662","analyzedAt":"2026-08-28T19:39:48.634Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}