PaddlePaddle/PaddleOCR · error · ResponseFormatError

Expected a JSON response body.

Error message

Expected a JSON response body.

What it means

ResponseFormatError with 'Expected a JSON response body.' means the HTTP request itself succeeded but resp.json() threw while decoding the body — the server returned an empty body or content that is not JSON (HTML, plain text, binary). The underlying decode error is preserved on `cause`. It comes from the private fetchJson<T>() used by most JSON API endpoints.

Source

Thrown at api_sdk/typescript/src/internal/http.ts:167

  async fetchResource(url: string, signal?: AbortSignal, timeoutMs?: number): Promise<ArrayBuffer> {
    const resp = await this.fetch(url, { method: "GET" }, signal, false, timeoutMs);
    return resp.arrayBuffer();
  }

  private async fetchJson<T>(
    url: string,
    init: RequestInit,
    signal?: AbortSignal,
    withAuth: boolean = true,
    timeoutMs?: number,
  ): Promise<T> {
    const resp = await this.fetch(url, init, signal, withAuth, timeoutMs);
    let payload: APIResponse<T>;
    try {
      payload = await resp.json() as APIResponse<T>;
    } catch (error) {
      throw new ResponseFormatError("Expected a JSON response body.", { cause: error });
    }
    if (payload.code !== undefined && payload.code !== 0) {
      throw new APIError(resp.status, payload.msg || "PaddleOCR official API request failed.");
    }
    if (!payload || typeof payload !== "object" || !("data" in payload)) {
      throw new ResponseFormatError("Response body is missing data.");
    }
    return payload.data;
  }

  private async fetch(
    url: string,
    init: RequestInit,
    signal?: AbortSignal,
    withAuth: boolean = true,
    timeoutMs?: number,
  ): Promise<Response> {
    const headers: Record<string, string> = {

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Log the actual body: catch the error and print e.cause plus re-run the request with the same headers via curl to see what the server really returned
  2. Verify the API base URL / endpoint configuration — the most common cause is hitting a host that serves HTML
  3. If a proxy or VPN sits between you and the API, exempt the API host or verify it does not rewrite responses
  4. If persistent and reproducible with curl, treat it as a service-side regression and report it with the request ID

Example fix

try {
  const status = await client.getJobStatus(jobId);
} catch (e) {
  if (e instanceof ResponseFormatError && /Expected a JSON/.test(e.message)) {
    // body was not JSON: dump cause for the raw decode failure
    console.error("Non-JSON body from server:", e.cause);
  }
}
Defensive patterns

Strategy: try-catch

Type guard

async function returnsJsonBody(url: string, init: RequestInit): Promise<boolean> {
  const r = await fetch(url, init);
  const ct = r.headers.get("content-type") ?? "";
  return ct.includes("application/json");
}

Try / catch

try {
  const status = await poller.getStatus(jobId);
} catch (e) {
  if (e instanceof ResponseFormatError && /Expected a JSON response body/.test(e.message)) {
    // server sent non-JSON: capture traffic via custom fetchImpl, check base URL
    throw new Error(`API returned non-JSON body: ${e.cause}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Any authenticated JSON call (submitJson, getJobStatus, getBatchStatus, token fetch) where the gateway responds 2xx with a non-JSON body: an HTML login/consent page, an empty 204, a captive portal, or a WAF block page that still returns 200.

Common situations: Wrong base URL pointing at a marketing page instead of the API host; corporate proxies injecting HTML; misconfigured API key routing the request to a docs page; server-side incidents returning empty bodies; HTTP/2 truncation.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/be0d3b34a50457d1. Report an issue: GitHub.