PaddlePaddle/PaddleOCR · error · AuthError

Token is required. Set PADDLEOCR_ACCESS_TOKEN or pass token

Error message

Token is required. Set PADDLEOCR_ACCESS_TOKEN or pass token option.

What it means

Thrown by unwrap_api_response in paddleocr/_api_client/_core.py:170 when a 2xx API response's JSON envelope has no object 'data' field. The PaddleOCR API contract wraps every payload as {code, msg, data}; after the code check passes, 'data' must be a JSON object. A missing, null, list, or scalar 'data' triggers this ResponseFormatError. It signals the server response deviated from the documented schema, not a client input problem.

Source

Thrown at api_sdk/typescript/src/client.ts:38

import type { ClientOptions, DocParsingRequest, OCRRequest, SaveResourceOptions } from "./models.js";
import { isDocumentParsingModel, isOCRModel, Model } from "./models.js";
import type { BatchStatus, DocParsingResult, Job, JobStatus, OCRResult } from "./results.js";

const DEFAULT_BASE_URL = "https://paddleocr.aistudio-app.com";

interface ResourceSavePlan {
  resourceUrl: string;
  filename: string;
}

export class PaddleOCRClient {
  private http: HttpClient;
  private poller: Poller;

  constructor(options: ClientOptions = {}) {
    const token = options.token || process.env.PADDLEOCR_ACCESS_TOKEN || "";
    if (!token) {
      throw new AuthError("Token is required. Set PADDLEOCR_ACCESS_TOKEN or pass token option.");
    }
    const baseUrl = options.baseUrl || process.env.PADDLEOCR_BASE_URL || DEFAULT_BASE_URL;
    const requestTimeout = options.requestTimeout || options.timeout || 300000;
    const pollTimeout = options.pollTimeout || options.timeout || 600000;

    this.http = new HttpClient(
      token,
      baseUrl,
      requestTimeout,
      options.fetch,
      options.clientPlatform,
    );
    this.poller = new Poller(this.http, pollTimeout);
  }

  async ocr(req: OCRRequest, options?: { signal?: AbortSignal }): Promise<OCRResult> {
    const job = await this.submitOcr(req, options);
    return this.waitOcrResult(job, options);

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Log the raw response body (catch ResponseFormatError and inspect response text via the SDK's http layer or a manual requests call) to see what the server actually returned
  2. Verify the base URL / API region configured on the client matches the current PaddleOCR API docs
  3. Check for SDK updates — an envelope change on the server usually gets a matching SDK release
  4. If a proxy interferes, bypass it or whitelist the API host
  5. Report the raw payload to PaddleOCR maintainers if the server is genuinely returning an malformed envelope

Example fix

// before
job_id = client.submit_file(...)

// after
from paddleocr._api_client.errors import ResponseFormatError
try:
    job_id = client.submit_file(...)
except ResponseFormatError as e:
    logger.error("Unexpected API envelope: %s", e)
    raise
Defensive patterns

Strategy: try-catch

Type guard

def is_api_envelope(payload: object) -> bool:
    return isinstance(payload, dict) and isinstance(payload.get("data"), dict)

Try / catch

from paddleocr._api_client.errors import ResponseFormatError
try:
    result = client.get_job_status(job_id)
except ResponseFormatError as e:
    # server broke the envelope contract; capture raw traffic and report
    logger.error("Malformed API envelope: %s", e)
    raise

Prevention

When it happens

Trigger: Any successful call to submit_url/submit_file/get_job_status/get_batch_status where the returned JSON lacks 'data' or has data as a string/list/null — e.g. a proxy or gateway returning {"code":0} with no data, or an API version change that renamed the field.

Common situations: Hitting a different/older API endpoint than the SDK targets; a corporate proxy or WAF rewriting responses; a service version bump changing the envelope; a maintenance page returning 200 with a JSON body without 'data'.

Related errors


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