Skip to content

Exceptions

All pyhaul exceptions inherit from HaulError. Transport errors from the underlying HTTP library (e.g. httpx.ReadTimeout, requests.ConnectionError) pass through unwrapped — you catch the types you already know.

Exception hierarchy

HaulError
├── PartialHaulError
├── UnexpectedStatusError
├── ServerMisconfiguredError
├── ContentRangeError
├── ControlFileError
└── DestinationError

Reference

Exception When Retryable?
PartialHaulError Stream ended before all bytes arrived. Yes — call haul() again; progress is saved
UnexpectedStatusError Server returned a non-download status (408, 429, 5xx, 404, …). Lets caller decide — check exc.is_transient / exc.is_server_error
ServerMisconfiguredError Server violated HTTP in a way that prevents safe resume. No
ContentRangeError 206 Content-Range doesn't match the requested range. Often yes
ControlFileError .part.ctrl is corrupt or version-mismatched. Auto-recovers — corrupt checkpoint is discarded on next attempt
DestinationError Destination path can't accommodate sidecar files. No — fix the path
(native) Transport errors (httpx.ReadTimeout, requests.ConnectionError, etc.) pass through unwrapped. Usually yes
TransportError Translated adapter / client I/O failure (timeout, TLS, reset, …) before pyhaul can complete the response. Usually yes

Details

pyhaul._types.HaulError

Bases: Exception

Base exception for pyhaul downloader errors.

pyhaul._types.PartialHaulError(reason: str = '')

Bases: HaulError

Stream ended before the full resource was retrieved.

Raised by haul() / haul_async() when the server closes the connection or the stream ends before all bytes arrive. The .part and .part.ctrl files persist on disk; a subsequent call resumes from where this one stopped.

Progress counters live in the :class:HaulState bag, not here.

pyhaul._types.UnexpectedStatusError(status_code: int, headers: TransportHeaders, reason: str = '')

Bases: HaulError

Server returned a non-download HTTP status code.

Carries structured metadata so callers can branch on status codes, inspect headers (e.g. Retry-After), or log the server's reason phrase without parsing the message string.

status_code: int = status_code instance-attribute

The HTTP status code (e.g. 429, 503, 404).

headers: TransportHeaders = headers instance-attribute

Response headers — immutable, case-insensitive.

reason: str = reason or f'unexpected HTTP {status_code}' instance-attribute

Human-readable summary, e.g. "unexpected HTTP 429".

is_transient: bool property

True when the status usually indicates a temporary condition worth retrying.

Includes common overload / upstream / CDN signals (e.g. 408, 425, 429, 5xx gateway and origin errors, and Cloudflare 520/522/524). For any HTTP 5xx without branching on this set, see :attr:is_server_error.

is_server_error: bool property

True for HTTP 5xx responses (status 500 ≤ code ≤ 599).

retry_after: str | None property

Raw Retry-After header value, if present (seconds or HTTP-date string).

retry_after_seconds: float | None property

Seconds until retry per Retry-After, or None if absent/unparsable.

Accepts delay-seconds (integer) and HTTP-date forms (RFC 9110 §10.2.3). For dates in the past, returns 0.0. Parsing only — pyhaul does not retry or cap sleeps.

The .headers attribute is a TransportHeaders — an immutable, case-insensitive mapping with multi-value support and automatic redaction of sensitive values in logs.

pyhaul._types.ServerMisconfiguredError

Bases: HaulError

The server violated protocol in a way that prevents safe download.

pyhaul._types.ContentRangeError

Bases: HaulError

Content-Range header doesn't match the expected range boundaries.

pyhaul._types.ControlFileError

Bases: HaulError

The control file is corrupt, unreadable, or inconsistent with the part file.

pyhaul._types.DestinationError

Bases: HaulError

The destination path cannot accommodate sidecar files (.part, .part.ctrl).

pyhaul.transport.errors.TransportError

Bases: HaulError

Base class for failures surfaced by a :class:pyhaul.transport.TransportSession.

pyhaul.transport.errors.TransportConnectionError(message: str)

Bases: TransportError, ConnectionError

Network-level failure (DNS, refused connection, reset, timeout, ...).

Subclasses builtin :exc:ConnectionError (and thus :exc:OSError) as well as :class:TransportError.

pyhaul.transport.errors.TransportTLSError

Bases: TransportError

TLS / certificate verification failure.

pyhaul.transport.errors.TransportHTTPError(message: str, *, status_code: int | None = None)

Bases: TransportError

HTTP response that is treated as an error by the adapter or engine.

pyhaul.transport.errors.TransportUnsupportedError

Bases: TransportError

The transport or server cannot satisfy a request (capability / policy).