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
- Raise the wait budget: waitForResult(jobId, { maxWaitTime: 10 * 60_000 }) — remember the unit is milliseconds
- On timeout, do not resubmit: resume polling the same jobId later with getStatus(jobId) since the job keeps running server-side
- Split huge documents into smaller submissions with narrower pageRanges so each finishes faster
- 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
- Remember maxWaitTime is milliseconds — audit any value < 1000 for unit mistakes
- Size the budget to the document (pages × per-page latency) with slack
- Persist jobIds so waits can resume across process restarts instead of blocking
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
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Job ${jobId} failed: ${errorMsg}
- Document parsing result item is missing result.layoutParsing
- Job ${job.jobId} is a ${job.task} job, not a ${expectedTask}
- Request timed out after ${timeoutMs}ms
- Unknown job state: ${data.state}
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/88cf1b6c77343eff.
Report an issue: GitHub.