PaddlePaddle/PaddleOCR · error · ResponseFormatError

Batch response is missing extractResult.

Error message

Batch response is missing extractResult.

What it means

ResponseFormatError with 'Batch response is missing extractResult.' is thrown by getBatchStatus() when the batch status response's data object is not a record containing an extractResult array. The SDK's batch contract requires data.extractResult to be an array of per-job status objects; its absence means the response shape is not a valid batch status payload.

Source

Thrown at api_sdk/typescript/src/internal/poller.ts:69

      if (status.state === "failed") {
        throw new JobFailedError(jobId, status.errorMsg || "Unknown error");
      }

      await this.sleep(Math.min(interval, Math.max(0, deadline - Date.now())), signal);
      interval = Math.min(interval * MULTIPLIER, MAX_INTERVAL);
    }

    throw new PollTimeoutError(jobId, this.maxWaitTime);
  }

  async getStatus(jobId: string, signal?: AbortSignal): Promise<JobStatus> {
    return normalizeStatus(jobId, await this.http.getJobStatus(jobId, signal));
  }

  async getBatchStatus(batchId: string, signal?: AbortSignal): Promise<BatchStatus> {
    const data = await this.http.getBatchStatus(batchId, signal);
    if (!isRecord(data) || !Array.isArray(data.extractResult)) {
      throw new ResponseFormatError("Batch response is missing extractResult.");
    }
    return {
      batchId,
      jobs: data.extractResult.map((item) => {
        if (!isRecord(item) || typeof item.jobId !== "string") {
          throw new ResponseFormatError("Batch extractResult item is missing jobId.");
        }
        return normalizeStatus(item.jobId, item);
      }),
    };
  }

  private sleep(ms: number, signal?: AbortSignal): Promise<void> {
    return new Promise((resolve, reject) => {
      const timer = setTimeout(resolve, ms);
      if (!signal) return;
      signal.addEventListener(
        "abort",

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Verify you are passing a batchId (returned at batch submission time), not a single jobId
  2. Capture the raw batch status response with a custom fetchImpl to see what data actually contains
  3. Align SDK and server versions — extractResult is part of the batch status contract
  4. Make test mocks return { data: { extractResult: [{ jobId, state, ... }] } }

Example fix

try {
  const batch = await poller.getBatchStatus(batchId);
} catch (e) {
  if (e instanceof ResponseFormatError && e.message.includes("extractResult")) {
    logger.error("Not a valid batch response for", batchId);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

const BATCH_ID_RE = /^batch-[\w-]+$/; // adjust to your server's format
function isPlausibleBatchId(id: string): boolean {
  return BATCH_ID_RE.test(id);
}

Type guard

function isBatchResponse(v: unknown): v is { extractResult: unknown[] } {
  return typeof v === "object" && v !== null && Array.isArray((v as any).extractResult);
}

Try / catch

try {
  const batch = await poller.getBatchStatus(batchId);
} catch (e) {
  if (e instanceof ResponseFormatError && e.message.includes("extractResult")) {
    // not retryable as-is: verify batchId provenance and API version
    throw new Error(`batchId '${batchId}' did not return a batch payload`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling getBatchStatus(batchId) where batchId is not a real batch (server returns an error-shaped or empty data object with 200), the endpoint version changed the field name, or a mock/stub omits extractResult.

Common situations: Passing a jobId instead of a batchId; batch retention expired server-side; SDK/server version drift renaming the field; test doubles returning simplified JSON.

Related errors


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