Skip to content

Exceptions

The AnafError hierarchy — transport, auth, and configuration failures. Business outcomes are typed values, not exceptions: see the error model.

anafpy.exceptions

Exception hierarchy for anafpy.

Per the design: exceptions are raised for transport / auth / programming errors. Business outcomes (e.g. an e-Factura nok rejection with its BR-RO findings) are returned as typed values, never raised.

AnafError

Bases: Exception

Base class for every error raised by anafpy.

AnafConfigError

Bases: AnafError

Invalid or missing configuration (credentials, paths, parameters).

AnafAuthError

Bases: AnafError

OAuth/authentication failure (bad credentials, expired refresh token, ...).

AnafTransportError

Bases: AnafError

A network-level failure talking to ANAF (connection, timeout, ...).

AnafResponseError

AnafResponseError(message: str, *, status_code: int, body: str | None = None)

Bases: AnafTransportError

ANAF returned a non-success HTTP status.

Attributes:

Name Type Description
status_code

the HTTP status code.

body

the (decoded) response body, if any, for diagnostics.

AnafWafRejectionError

AnafWafRejectionError(message: str, *, status_code: int = 200, body: str | None = None, support_id: str | None = None)

Bases: AnafResponseError

ANAF's web-application firewall refused the request body.

The F5 fronting ANAF's hosts scans request bodies and answers its Request Rejected HTML page — with HTTP 200 — when one matches an attack signature. Legitimate, ANAF-accepted invoices do: a relative path in xsi:schemaLocation reads as path traversal, ;CP in an address reads as a shell command (see docs/anaf-reference/efactura/api.md §6). Raising keeps the block page from ever being mistaken for a result; it is ANAF's infrastructure refusing the call, not a verdict on the document.

Attributes:

Name Type Description
support_id

the F5 incident id from the block page (quote it to ANAF), or None if the page carried none.

AnafDownloadExpiredError

AnafDownloadExpiredError(message: str, *, status_code: int = 200, body: str | None = None, message_id: str | None = None)

Bases: AnafResponseError

The message left ANAF's 60-day download window — it can never be fetched.

descarcare answers HTTP 200 with the JSON note {"eroare": "Fisierul nu mai poate fi descarcat pentru ca a trecut perioada de 60 de zile in care este disponibil", …} (see docs/anaf-reference/efactura/api.md §4.1). This is terminal: the file is gone from the SPV, no retry can ever succeed, and a caller may safely stop asking for this id for good.

Reachable in normal operation, not only through caller error: listaMesaje and descarcare anchor their 60 days differently, so ANAF lists messages it then refuses to hand over. A first sync — or one catching up after a gap — with a 60-day lookback walks into the boundary band.

Only the recognised wording raises this; every other non-ZIP descarcare body (unknown id, malformed request) stays a plain :class:AnafResponseError, which is worth retrying or fixing.

Attributes:

Name Type Description
message_id

the descarcare id that can no longer be downloaded, or None if the raiser had none to hand.

AnafRateLimitError

AnafRateLimitError(message: str = 'ANAF rate limit exceeded (429)', *, retry_after: float | None = None, body: str | None = None)

Bases: AnafResponseError

HTTP 429 — ANAF's rate limit (1000 req/min) was exceeded.

The client does not auto-retry; it surfaces retry_after (seconds) so the caller can decide how to back off.