Skip to content

Map the failure field of the task status response #778

Open

Description

@edeandrea

Background

#776 added errorMessage to TaskStatusPollResponse, mapped from the error_message that Docling Serve returns on a failed task (see #775). Upstream TaskStatusResponse carries a second, richer failure field that we still don't map:

class TaskStatusResponse(BaseModel):
    ...
    error_message: Optional[str] = None            # mapped by #776
    failure: Optional[PublicFailureInfo] = None    # not mapped


class PublicFailureInfo(BaseModel):
    category: FailureCategory
    message: str
    retryable: bool
    phase: FailurePhase
    details: dict[str, str] = Field(default_factory=dict)

Why it is worth mapping

retryable is the main draw: it lets a caller decide whether to resubmit without parsing an error string. category and phase let a caller tell a bad input apart from a service outage.

failure.message is also more specific than error_message for the same failure. error_message is built by build_public_task_error, which returns the real exception text for only four exception types and otherwise returns the constant "Internal processing error.". For those same cases failure.message says things like "Task exceeded the allowed execution time." or "Source document could not be reached.".

Why it was left out of #776

  • Ray only. Of the three orchestrators in docling-jobkit, only the Ray dispatcher populates failure. The local orchestrator (what DoclingServeContainer runs) and the RQ orchestrator set error_message only.
  • v1.25.0+. failure first appears in docling-serve v1.25.0, whereas error_message is returned by every tag in our compatibility table, back to v1.18.0.

error_message was therefore the right field for the bug fix. failure is additive value for Ray deployments.

Decision needed first: unknown enum values

Mapping failure means introducing FailureCategory (9 values today) and FailurePhase (4 values) into docling-serve-api.

We have no policy for unknown enum values anywhere in the repo — no READ_UNKNOWN_ENUM_VALUES_AS_NULL, no @JsonEnumDefaultValue. A constant added upstream would be a hard deserialization failure across the whole version range we test against.

TaskStatus gets away with this only because its value domain is genuinely frozen at four: the values actually assigned come from jobkit's own TaskStatus, not the wider ConversionStatus that the response model nominally declares. FailureCategory is documented upstream as shared across task and document scope and extensible, so it will grow.

Options:

  1. Map category/phase as String. No breakage risk, no type safety.
  2. Map as enums with an UNKNOWN constant and @JsonEnumDefaultValue. Needs to hold for both the Jackson 2 and Jackson 3 mappers, including user-supplied ones.
  3. Map as enums and set READ_UNKNOWN_ENUM_VALUES_AS_NULL on both default mappers. Does not help a consumer who brings their own mapper.

Worth settling repo-wide rather than only for this field.

Scope

  • Add TaskFailureInfo to ai.docling.serve.api.task.response, following the Lombok / @Jacksonized / builder conventions already used by TaskStatusPollResponse and TaskStatusMetadata.
  • Add the failure field to TaskStatusPollResponse.
  • Resolve the enum question above.
  • Do not change the AsyncOperations failure message to prefer failure.message. It is Ray-only, so error_message stays the source for the message text; failure is data for callers.

Related drift

Two other places where our mirrors have fallen behind upstream, same root cause. Possibly worth folding in, possibly worth splitting out:

  • TaskStatusMetadata is missing num_partially_succeeded (upstream TaskProcessingMeta has five fields, we map four).
  • ErrorItem is missing category and page_no.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions