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 (429, 503, 404, …). Lets caller decide — check exc.is_transient
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

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 for 429 (Too Many Requests) and 503 (Service Unavailable).

retry_after: str | None property

Value of the Retry-After header, if present.

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).