PaddlePaddle/PaddleOCR · error · InvalidRequestError

Model ${model} is not a document parsing model.

Error message

Model ${model} is not a document parsing model.

What it means

Thrown by extract_job_id in paddleocr/_api_client/_core.py:177 when the unwrapped 'data' object of a job-submission response does not contain a non-empty string 'jobId'. After a successful submit, the SDK must extract jobId to poll the job; a missing, empty, or non-string jobId makes the response unusable. This is a ResponseFormatError, meaning the server broke the documented response schema.

Source

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

    const job = await this.submitOcr(req, options);
    return this.waitOcrResult(job, options);
  }

  async parseDocument(req: DocParsingRequest, options?: { signal?: AbortSignal }): Promise<DocParsingResult> {
    const job = await this.submitDocumentParsing(req, options);
    return this.waitDocumentParsingResult(job, options);
  }

  async submitOcr(req: OCRRequest, options?: { signal?: AbortSignal }): Promise<Job> {
    const model = req.model ?? Model.PPOCRv6;
    const jobId = await this.submit(model, "ocr", req, options?.signal);
    return { jobId, model, task: "ocr", pageRanges: req.pageRanges, batchId: req.batchId };
  }

  async submitDocumentParsing(req: DocParsingRequest, options?: { signal?: AbortSignal }): Promise<Job> {
    const model = req.model ?? Model.PaddleOCRVL16;
    if (!isDocumentParsingModel(model)) {
      throw new InvalidRequestError(`Model ${model} is not a document parsing model.`);
    }
    const jobId = await this.submit(model, "document_parsing", req, options?.signal);
    return { jobId, model, task: "document_parsing", pageRanges: req.pageRanges, batchId: req.batchId };
  }

  async waitOcrResult(job: Job | string, options?: { signal?: AbortSignal }): Promise<OCRResult> {
    const resolved = this.resolveJob(job, "ocr");
    const jsonlData = await this.poller.pollUntilDone(resolved.jobId, options?.signal);
    return this.parseOCRResult(resolved.jobId, jsonlData);
  }

  async waitDocumentParsingResult(job: Job | string, options?: { signal?: AbortSignal }): Promise<DocParsingResult> {
    const resolved = this.resolveJob(job, "document_parsing");
    const jsonlData = await this.poller.pollUntilDone(resolved.jobId, options?.signal);
    return this.parseDocParsingResult(resolved.jobId, jsonlData);
  }

  async getStatus(jobId: string, options?: { signal?: AbortSignal }): Promise<JobStatus> {

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Capture and inspect the full response body to confirm what keys 'data' actually contains
  2. Verify the SDK version matches the API version you are calling (upgrade paddleocr)
  3. If using a mock server in tests, make it return {"code":0, "data":{"jobId":"<non-empty-string>"}}
  4. Check whether a proxy or gateway is truncating/modifying the response

Example fix

# mock/test server fix
# before
{"code": 0, "data": {"id": "abc123"}}
# after
{"code": 0, "data": {"jobId": "abc123"}}
Defensive patterns

Strategy: validation

Type guard

def has_job_id(data: dict) -> bool:
    jid = data.get("jobId")
    return isinstance(jid, str) and bool(jid.strip())

Try / catch

from paddleocr._api_client.errors import ResponseFormatError
try:
    job_id = client.submit_file(model, path, {})
except ResponseFormatError as e:
    if "jobId" in str(e):
        logger.error("Submit response lacked jobId; dumping and retrying once")
        raise

Prevention

When it happens

Trigger: Calling client.submit_url() or client.submit_file() (or the async variants) where the 2xx response's data object lacks 'jobId' — e.g. data is {} or contains an id under a different key.

Common situations: API version drift renaming jobId; a mock/test server that returns a partial envelope; middleware stripping fields; hitting the wrong endpoint that returns a valid envelope with different content.

Related errors


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