{"record":{"id":"510b20ec46f77b32","repo":"docling-project/docling","slug":"result-for-task-task-id-has-expired","errorCode":null,"errorMessage":"Result for task {task_id} has expired.","messagePattern":"Result for task (.+?) has expired\\.","errorType":"exception","errorClass":"ResultExpiredError","httpStatus":null,"severity":"error","filePath":"docling/service_client/client.py","lineNumber":673,"sourceCode":"\n        now = datetime.now(tz=retry_at.tzinfo or timezone.utc)\n        return max(0.0, (retry_at - now).total_seconds())\n\n    def _raise_for_result_404(\n        self,\n        task_id: str,\n        response: httpx.Response,\n        last_status: TaskStatusResponse | None,\n    ) -> None:\n        detail = self._http_error_detail(response)\n        if detail == \"Task not found.\":\n            raise TaskNotFoundError(f\"Task {task_id} was not found.\")\n        if detail is not None and detail.startswith(\"Task result not found\"):\n            if last_status is not None and is_terminal_task_status(last_status):\n                if last_status.task_status == \"failure\":\n                    message = last_status.error_message or f\"Task {task_id} failed.\"\n                    raise TaskExecutionError(message, failure=last_status.failure)\n                raise ResultExpiredError(f\"Result for task {task_id} has expired.\")\n            raise ResultNotReadyError(f\"Result for task {task_id} is not ready.\")\n        raise ServiceError(\n            \"Unexpected result lookup error.\",\n            status_code=response.status_code,\n            detail=detail,\n        )\n\n    def _raise_if_task_failure_result(self, response: httpx.Response) -> None:\n        content_type = response.headers.get(\"content-type\", \"\")\n        if \"json\" not in content_type.lower():\n            return\n\n        try:\n            payload = response.json()\n        except ValueError:\n            return\n\n        if not isinstance(payload, dict) or payload.get(\"kind\") != \"TaskFailureResult\":","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/service_client/client.py#L655-L691","documentation":"Raised as ResultExpiredError when the result endpoint answers 'Task result not found', the last status is terminal (but not failure), meaning the task completed yet its stored result artifact is no longer available. Unlike a not-ready state, retrying will not help: the service has discarded the result, typically due to its result-retention policy.","triggerScenarios":"Calling result retrieval for a task whose last TaskStatusResponse is a terminal success status while the service returns 404 detail starting with 'Task result not found' — i.e. the task finished but the artifact was expired/GC'd.","commonSituations":"Collecting results hours or days after completion when the service only retains artifacts briefly; restarting a service with ephemeral storage; queue-backed deployments where completed results are pruned aggressively.","solutions":["Collect job results promptly after completion instead of long-delayed polling.","Re-submit the conversion to regenerate the result if it has expired.","If you control the deployment, increase the service's result retention/TTL configuration.","Persist converted output yourself (e.g. to object storage) as soon as a result is obtained."],"exampleFix":"# before\nresult = job.result()  # days later: ResultExpiredError\n\n# after\nfrom docling.service_client.exceptions import ResultExpiredError\n\ntry:\n    result = job.result()\nexcept ResultExpiredError:\n    job = client.submit(source)  # regenerate\n    result = job.result()\n    save_to_storage(result)      # persist immediately","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"from docling.service_client.exceptions import ResultExpiredError\n\ntry:\n    result = job.result()\nexcept ResultExpiredError:\n    job = client.submit(source)      # regenerate the artifact\n    result = job.result()\n    persist(result)                   # keep your own copy","preventionTips":["Fetch results immediately after terminal status.","Persist converted output to your own storage.","Size the service result TTL to your workload cadence.","Treat expired results as cache misses, not errors."],"tags":["task","expiry","service-client","lifecycle"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}