PaddlePaddle/PaddleOCR · warning · PollTimeoutError

Timed out after ${timeoutMs}ms waiting for job ${jobId}

Error message

Timed out after ${timeoutMs}ms waiting for job ${jobId}

What it means

PollTimeoutError is thrown by the poller's main loop when the overall maxWaitTime budget is exhausted while the job is still pending or running — the wait loop deadline passed before the job reached 'done' or 'failed'. The jobId and the configured timeoutMs are exposed as properties. The job itself may still complete server-side; only the local wait gave up.

Source

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

      const remaining = deadline - Date.now();
      const data = await this.withPollTimeout(jobId, remaining, () => this.http.getJobStatus(jobId, signal, remaining));
      const status = normalizeStatus(jobId, data);

      if (status.state === "done") {
        const jsonUrl = resultJsonUrl(data);
        const resultRemaining = deadline - Date.now();
        return await this.withPollTimeout(jobId, resultRemaining, () => this.http.fetchJsonl(jsonUrl, signal, resultRemaining));
      }

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

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Raise the wait budget: waitForResult(jobId, { maxWaitTime: 10 * 60_000 }) — remember the unit is milliseconds
  2. On timeout, do not resubmit: resume polling the same jobId later with getStatus(jobId) since the job keeps running server-side
  3. Split huge documents into smaller submissions with narrower pageRanges so each finishes faster
  4. For serverless hosts, poll asynchronously (persist jobId, poll on the next invocation) instead of blocking

Example fix

// before
const result = await poller.waitForResult(jobId); // default budget too small

// after (resume instead of resubmitting)
let result;
try {
  result = await poller.waitForResult(jobId, { maxWaitTime: 15 * 60_000 });
} catch (e) {
  if (e instanceof PollTimeoutError) {
    result = await poller.waitForResult(e.jobId, { maxWaitTime: 15 * 60_000 });
  }
}
Defensive patterns

Strategy: retry

Validate before calling

function budgetMatchesExpectation(maxWaitTimeMs: number, pages: number): boolean {
  const msPerPage = 5_000; // conservative
  return maxWaitTimeMs > pages * msPerPage;
}

Type guard

function isPollTimeout(e: unknown): e is PollTimeoutError {
  return e instanceof PollTimeoutError;
}

Try / catch

try {
  result = await poller.waitForResult(jobId, { maxWaitTime: 15 * 60_000 });
} catch (e) {
  if (e instanceof PollTimeoutError) {
    // job still runs server-side: resume polling the SAME jobId, never resubmit
    result = await poller.waitForResult(e.jobId, { maxWaitTime: 15 * 60_000 });
  } else throw e;
}

Prevention

When it happens

Trigger: Waiting on a large or queued document that legitimately takes longer than maxWaitTime (default budget); jobs queued behind rate limits; overloaded backend during peak hours; maxWaitTime accidentally set very low or in the wrong unit (seconds vs ms).

Common situations: 1000-page PDFs processed slowly; free-tier queues during peak; developers passing 30 meaning 30 seconds but the SDK reading milliseconds; tight deadlines in serverless functions that must respond quickly.

Understand the failure class

Related errors


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