{"record":{"id":"14db0ce855fe2cd7","repo":"different-ai/openwork","slug":"den-request-invalid-json","errorCode":"den_request_invalid_json","errorMessage":"den_request_invalid_json","messagePattern":"den_request_invalid_json","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/server/src/cloud-provider-sync.ts","lineNumber":352,"sourceCode":"  let response: Response;\n  try {\n    response = await fetchImpl(`${session.baseUrl}${path}`, {\n      headers: {\n        Accept: \"application/json\",\n        Authorization: `Bearer ${session.token}`,\n        \"x-openwork-legacy-org-id\": session.orgId,\n      },\n      signal: AbortSignal.timeout(requestTimeoutMs),\n    });\n  } catch (error) {\n    throw new Error(error instanceof Error ? `den_request_failed: ${error.message}` : \"den_request_failed\");\n  }\n  if (!response.ok) throw new Error(`den_request_failed_${response.status}`);\n  try {\n    const payload: unknown = await response.json();\n    return payload;\n  } catch {\n    throw new Error(\"den_request_invalid_json\");\n  }\n}\n\nasync function fetchProviders(\n  fetchImpl: typeof globalThis.fetch,\n  session: CloudProviderDenSession,\n): Promise<DenProviderConnection[]> {\n  const providers = parseProviderList(await requestJson(fetchImpl, session, \"/v1/llm-providers\"));\n  return Promise.all(\n    providers.map(async (provider) =>\n      parseProviderConnection(\n        await requestJson(fetchImpl, session, `/v1/llm-providers/${encodeURIComponent(provider.id)}/connect`),\n        provider.id,\n      )),\n  );\n}\n\nfunction stableValue(value: unknown): unknown {","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/cloud-provider-sync.ts#L334-L370","documentation":"Error thrown by the cloud provider sync when the response body from a Den/cloud endpoint cannot be parsed as JSON. It indicates a malformed or non-JSON reply (e.g., HTML error page, empty body, or truncated response) from the remote provider-sync API. Callers should treat it as a transient or upstream server issue, not a client configuration problem; retrying and inspecting the raw response body is the usual next step.","triggerScenarios":"A fetchProviders/providers call receives a 200 response whose body is HTML (proxy/login page), empty, or truncated, so response.json() rejects.","commonSituations":"Corporate proxy or captive portal returns an HTML page with 200; hitting the wrong URL (e.g. a docs page); gateway returning gzip-corrupted or empty bodies; server temporarily returning plain-text errors.","solutions":["Log response.status and the first ~200 chars of the raw body before parsing to identify what the server actually returned","Verify the Den base URL points at the API host (api.openworklabs.com/mcp/agent style) and not a UI route","Check for proxies/VPNs/captive portals intercepting the request and returning HTML with 200","Retry with backoff; transient gateways sometimes mangle bodies"],"exampleFix":"// before\nconst payload: unknown = await response.json();\n// after\nconst raw = await response.text();\nlet payload: unknown;\ntry { payload = JSON.parse(raw); }\ncatch { throw new Error(`den_request_invalid_json: ${raw.slice(0, 200)}`); }","handlingStrategy":"retry","validationCode":"const head = await fetch(url, { method: \"HEAD\" }); if (!String(head.headers.get(\"content-type\")).includes(\"application/json\")) throw new Error(\"endpoint not JSON\");","typeGuard":"function isJsonContentType(res: Response): boolean { return String(res.headers.get(\"content-type\") || \"\").includes(\"application/json\"); }","tryCatchPattern":"try { return await requestJson(fetchImpl, url, session); } catch (e) { if (e instanceof Error && e.message === \"den_request_invalid_json\") { await sleep(backoff(attempt)); return requestJson(fetchImpl, url, session); } throw e; }","preventionTips":["Verify the Den base URL resolves to the API, not an HTML page","Monitor for proxy/captive-portal HTML responses","Retry transient parse failures with backoff","Surface raw body snippets in telemetry"],"tags":["network","json","cloud-api"],"backgroundTag":"invalid-json-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}