Errors¶
Every non-success response from DHIS2 raises a typed exception. The hierarchy is rooted at Dhis2ClientError and branches into four leaves: Dhis2ApiError (any HTTP non-success), AuthenticationError (401 / 403 specifically, on top of Dhis2ApiError), OAuth2FlowError (raised by the OAuth2 PKCE flow when token exchange fails), UnsupportedVersionError (raised on connect() when the live DHIS2 has no generated module).
Worked example — branch on Dhis2ApiError¶
from dhis2w_client import Dhis2ApiError
from dhis2w_core.client_context import open_client
from dhis2w_core.profile import profile_from_env
async with open_client(profile_from_env()) as client:
try:
# `delete_bulk` takes (resource_type, uids).
await client.metadata.delete_bulk("dataElements", ["doesNotExist"])
except Dhis2ApiError as exc:
print(f"HTTP {exc.status_code}: {exc.message}")
# `web_message()` materialises the typed envelope when DHIS2 returned one;
# returns None on errors whose body isn't a WebMessage (network 500s, etc.).
wm = exc.web_message()
if wm is not None and wm.response is not None:
for c in wm.response.conflicts or []:
print(f" conflict: {c.object} -> {c.value}")
Worked example — narrow except for auth failures¶
from dhis2w_client import AuthenticationError, Dhis2ApiError
try:
await client.system.me()
except AuthenticationError as exc:
# Bad PAT / expired / wrong username/password. Distinct from
# other 4xx failures so callers can prompt for re-auth specifically.
print(f"re-auth needed: {exc.message}")
except Dhis2ApiError as exc:
# Any other DHIS2-side error (404, 409, 500, ...).
print(f"unexpected: {exc.status_code} {exc.message}")
Worked example — UnsupportedVersionError¶
from dhis2w_client import Dhis2Client, BasicAuth
from dhis2w_client.errors import UnsupportedVersionError
# `allow_version_fallback=False` (the default) fails fast when the live
# DHIS2 is on a version without a committed `generated/v{NN}` tree.
try:
async with Dhis2Client("https://newer-dhis2.example", auth=BasicAuth(...)) as client:
...
except UnsupportedVersionError as exc:
# `exc.version` is the unsupported version key (e.g. 'v44');
# `exc.available` is the list of trees the client does have.
print(f"no generated module for {exc.version}; available: {exc.available}")
print("run `d2w codegen generate --url ...` to add one")
Pass allow_version_fallback=True on the client constructor (or via open_client(..., allow_version_fallback=True)) to use the nearest-lower populated version instead of raising.
Worked example: examples/v42/client/error_handling.py.
errors
¶
Exception hierarchy for dhis2w-client — shared across all version trees.
Errors carry no version-specific behaviour, so they live in one module rather than being
copied per version. A single shared hierarchy means except dhis2w_client.Dhis2ApiError
catches errors from a client bound to any DHIS2 major (v41/v42/v43), not just the baseline.
Classes¶
Dhis2ClientError
¶
Dhis2ApiError
¶
Bases: Dhis2ClientError
Raised when the DHIS2 API returns a non-success response.
Source code in packages/dhis2w-client/src/dhis2w_client/errors.py
Attributes¶
web_message
property
¶
Parse body as a WebMessageResponse when the shape matches, else None.
DHIS2 returns the envelope on errors too (e.g. 409 on /api/dataValueSets
with status=WARNING + populated conflicts[]), so callers can inspect
import counts and per-row rejections without re-parsing. The error-envelope
shape is stable across majors, so the baseline (v42) model parses any tree's body.
Imported lazily because envelopes.py pulls in the generated OAS tree,
which itself imports client.py (for the generated resource
accessors), and client.py imports errors.py — classic cycle. The
web_message call-site runs only after the package is fully loaded,
so the late import is safe.
Functions¶
__init__(status_code, message, body=None)
¶
Capture HTTP status, message, and optional response body.
Source code in packages/dhis2w-client/src/dhis2w_client/errors.py
AuthenticationError
¶
Bases: Dhis2ClientError
Raised when authentication fails or tokens are invalid.
OAuth2FlowError
¶
Bases: Dhis2ClientError
Raised when the OAuth 2.1 authorization-code flow fails.
UnsupportedVersionError
¶
Bases: Dhis2ClientError
Raised when the DHIS2 instance version has no generated client and fallback is disabled.
Source code in packages/dhis2w-client/src/dhis2w_client/errors.py
Functions¶
__init__(version, available)
¶
Capture the reported version and the list of versions we have codegen for.
Source code in packages/dhis2w-client/src/dhis2w_client/errors.py
VersionPinMismatchError
¶
Bases: UnsupportedVersionError
Raised when Dhis2Client(version=...) pins a major different from the server's reported version.
Source code in packages/dhis2w-client/src/dhis2w_client/errors.py
Functions¶
__init__(pinned, reported)
¶
Capture the pinned generated tree + the wire-reported server version.
Source code in packages/dhis2w-client/src/dhis2w_client/errors.py
Functions¶
format_unauthorized_message(method, path, www_authenticate)
¶
Build a 401 message, surfacing actionable hints for known DHIS2 OAuth2 failures.