Skip to content

WarmHubError

Class: warmhub.WarmHubError

WarmHubError(code: str, message: str, status: int | None = None, hint: str | None = None, retry_after: float | None = None, error_code: str | None = None, details: ErrorDetails | Mapping[str, Any] | None = None)

Normalized error for transport, tRPC, validation, and backend failures.

isinstance(err, WarmHubError) is the exact Python analogue of TypeScript’s isWarmHubError(err).

Cause. Raised when a request fails: a transport error, a tRPC error envelope, a validation rejection, or a backend fault. kind says which.

Retryability. Depends on kind, so do not assume. Call is_retryable; it is True for NETWORK, CANCELLED, BACKEND, and RATE_LIMITED and False for VALIDATION_ERROR and NOT_FOUND, which no retry can fix.

Corrective action. For a retryable kind, wait retry_after seconds and retry. For a conflict, use is_conflict, re-read, and reapply with the current version. Otherwise fix the request the message names.

name = 'WarmHubError'

Mirrors TypeScript’s this.name = 'WarmHubError'. to_warmhub_error reads it to recognize an error raised by a different copy of the SDK, where an isinstance check fails.

submission_id = None

The submission this chunk belonged to.

event_request_id = None

The chunk’s deterministic event-request identity.

chunk_ordinal = None

The chunk’s zero-based position in the submission.

code = code

Stable SDK error code or pass-through backend domain code.

message = message

Documentation is not yet available.

status = status

HTTP status from the failing response, when one was available.

hint = hint

Optional human-readable hint surfaced by the backend.

retry_after = None if retry_after is None else min(max(retry_after, 0.0), MAX_RETRY_AFTER_SECONDS)

Seconds to wait before retrying. Present on RATE_LIMITED.

Clamped to MAX_RETRY_AFTER_SECONDS HERE rather than at the one construction site that reads a header. The value reaches this class from four paths — header, REST body, tRPC envelope, and re-normalization — and capping one of them left the stated invariant (“one hostile response must not put the client to sleep for a week”) true only of the path that happened to be written last.

error_code = error_code

Canonical domain code from the response body. Set iff the backend wire carried a structured error.code.

details = decode_error_details(details) if isinstance(details, Mapping) else details

Documentation is not yet available.

kind

Alias for code, matching TypeScript’s get kind().

expected_version

The version the caller asserted, on a lost optimistic-concurrency race. None unless details.reason is "expected_version_mismatch" — pair with current_version.

current_version

The version the server actually holds. Re-read at this version and retry; see expected_version.

lease_expires_at

ISO-8601 instant the blocking read lease expires, or None.

validation_issues

Per-field validation issues. Empty, not None, when the wire carried a different reason — a caller iterating this needs no guard, and an empty loop body is the correct behavior for “no issues reported”.

reset_at

ISO-8601 instant a rate limit lifts, or None.

Distinct from retry_after, which is the transport-level relative delay and is populated from the response envelope rather than from details. When the backend sends structured rate_limit_reset details, both are present and they agree; when it sends only one, the other stays None.

backend_code

Deprecated alias for error_code.

Retained because TypeScript still exposes backendCode during the GH-3533 migration window; dropping it would be a silent surface difference between the clients.