docling-project/docling · error · TaskNotFoundError

Task {task_id} was not found.

Error message

Task {task_id} was not found.

What it means

TaskNotFoundError raised by the WebSocket status watcher when the service sends an error frame with exactly 'Task not found.' over WS /v1/status/ws/{task_id}. It means the task id is unknown to the service — expired from the result backend, never existed, or was purged after completion.

Source

Thrown at docling/service_client/watchers.py:57

) -> float:
    elapsed = time.monotonic() - poll_started
    remaining = deadline - time.monotonic()
    if remaining <= 0:
        return 0.0
    return max(0.0, min(poll_interval, remaining) - elapsed)


def _process_ws_envelope(
    envelope: WebsocketMessage,
    task_id: str,
) -> TaskStatusResponse | None:
    """Return the TaskStatusResponse from an envelope, or None for CONNECTION frames.

    Raises TaskNotFoundError or ServiceUnavailableError on error frames.
    """
    if envelope.error:
        if envelope.error == "Task not found.":
            raise TaskNotFoundError(f"Task {task_id} was not found.")
        raise ServiceUnavailableError(
            "WebSocket status stream failed.",
            detail=envelope.error,
        )
    return envelope.task


class StatusWatcher(Protocol):
    """Protocol for job status watchers."""

    def iter_updates(
        self, task_id: str, timeout: float | None
    ) -> Iterator[TaskStatusResponse]: ...

    def wait_for_terminal(
        self, task_id: str, timeout: float | None
    ) -> TaskStatusResponse: ...

View on GitHub (pinned to 61d76f1ff3)

Solutions

  1. Handle TaskNotFoundError as terminal — resubmit the conversion instead of re-polling
  2. If tasks must survive restarts, configure a persistent result backend (redis/database) in docling-serve
  3. Store task ids only as long as the service's task TTL allows

Example fix

try:
    status = watcher.wait_for_terminal(task_id)
except TaskNotFoundError:
    result = client.submit(Path('doc.pdf'))  # resubmit
Defensive patterns

Strategy: try-catch

Type guard

def is_task_not_found(exc: BaseException) -> bool:
    return isinstance(exc, TaskNotFoundError)

Try / catch

from docling.service_client.exceptions import TaskNotFoundError

try:
    status = watcher.wait_for_terminal(task_id)
except TaskNotFoundError:
    task_id = resubmit_and_get_new_id()

Prevention

When it happens

Trigger: Opening the status WebSocket for a task id that finished and was evicted, a fabricated/typo'd id, or a task record lost after a service restart while the client was waiting.

Common situations: Waiting on tasks across a service redeploy (in-memory task store wiped); result TTL expiry before the client re-attached; copy-paste errors in persisted task ids.

Related errors


AI-assisted analysis of docling-project/docling@61d76f1ff3 (2026-08-14). Data as JSON: /api/errors/376e353132dd64ba. Report an issue: GitHub.