different-ai/openwork · error · Error

den_request_invalid_json

den_request_invalid_json

Error message

den_request_invalid_json

What it means

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.

Source

Thrown at apps/server/src/cloud-provider-sync.ts:352

  let response: Response;
  try {
    response = await fetchImpl(`${session.baseUrl}${path}`, {
      headers: {
        Accept: "application/json",
        Authorization: `Bearer ${session.token}`,
        "x-openwork-legacy-org-id": session.orgId,
      },
      signal: AbortSignal.timeout(requestTimeoutMs),
    });
  } catch (error) {
    throw new Error(error instanceof Error ? `den_request_failed: ${error.message}` : "den_request_failed");
  }
  if (!response.ok) throw new Error(`den_request_failed_${response.status}`);
  try {
    const payload: unknown = await response.json();
    return payload;
  } catch {
    throw new Error("den_request_invalid_json");
  }
}

async function fetchProviders(
  fetchImpl: typeof globalThis.fetch,
  session: CloudProviderDenSession,
): Promise<DenProviderConnection[]> {
  const providers = parseProviderList(await requestJson(fetchImpl, session, "/v1/llm-providers"));
  return Promise.all(
    providers.map(async (provider) =>
      parseProviderConnection(
        await requestJson(fetchImpl, session, `/v1/llm-providers/${encodeURIComponent(provider.id)}/connect`),
        provider.id,
      )),
  );
}

function stableValue(value: unknown): unknown {

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Log response.status and the first ~200 chars of the raw body before parsing to identify what the server actually returned
  2. Verify the Den base URL points at the API host (api.openworklabs.com/mcp/agent style) and not a UI route
  3. Check for proxies/VPNs/captive portals intercepting the request and returning HTML with 200
  4. Retry with backoff; transient gateways sometimes mangle bodies

Example fix

// before
const payload: unknown = await response.json();
// after
const raw = await response.text();
let payload: unknown;
try { payload = JSON.parse(raw); }
catch { throw new Error(`den_request_invalid_json: ${raw.slice(0, 200)}`); }
Defensive patterns

Strategy: retry

Validate before calling

const head = await fetch(url, { method: "HEAD" }); if (!String(head.headers.get("content-type")).includes("application/json")) throw new Error("endpoint not JSON");

Type guard

function isJsonContentType(res: Response): boolean { return String(res.headers.get("content-type") || "").includes("application/json"); }

Try / catch

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; }

Prevention

When it happens

Trigger: A fetchProviders/providers call receives a 200 response whose body is HTML (proxy/login page), empty, or truncated, so response.json() rejects.

Common situations: 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.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/14db0ce855fe2cd7. Report an issue: GitHub.