niwaki.exceptions¶
Niwaki SDK — public exception hierarchy.
All errors raised by the SDK are subclasses of NiwakiError so callers can
write a single broad except NiwakiError or target a specific branch:
from niwaki.exceptions import (
NiwakiError, # catch-all
AuthError, # any authentication failure
LoginError, # wrong credentials
TokenRefreshError, # /aaaRefresh.json failed
SessionExpiredError, # token dead, re-login also failed
TransportError, # any network-level error
ConnectionError, # host unreachable
TimeoutError, # request too slow
TLSError, # SSL/TLS certificate issue
APIError, # APIC returned 4xx / 5xx
UnauthorizedError, # 401 — token rejected by APIC
ForbiddenError, # 403 — insufficient privileges
NotFoundError, # 404 — MO does not exist
ServerError, # 5xx — APIC internal error
DeserializationError, # response cannot be parsed into a typed model
StagedPushError, # staged design push partially succeeded
SubscriptionError, # any object-subscription (WebSocket push) failure
StatsClassNotSubscribableError, # subscribed to a stats class — never pushes
SubscribeRejectedError, # the APIC rejected a subscription=yes request
SubscriptionLostError, # a subscription could not be recovered
SubscriptionLostReason, # which recovery path was exhausted (see .reason)
)
Hierarchy:
NiwakiError
├── AuthError
│ ├── LoginError
│ ├── TokenRefreshError
│ └── SessionExpiredError
├── TransportError
│ ├── ConnectionError
│ ├── TimeoutError
│ └── TLSError
├── APIError
│ ├── UnauthorizedError
│ ├── ForbiddenError
│ ├── NotFoundError
│ └── ServerError
├── DeserializationError
├── NoResultError (query .one() matched nothing)
├── MultipleResultsError (query .one() matched several)
├── DesignError
│ ├── UnknownMakerError (also an AttributeError)
│ ├── DuplicateDeclarationError
│ ├── UnresolvedReferenceError
│ ├── AmbiguousBindError
│ └── StagedPushError
└── SubscriptionError
├── StatsClassNotSubscribableError
├── SubscribeRejectedError (also an APIError)
└── SubscriptionLostError (.reason: SubscriptionLostReason)
- exception niwaki.exceptions.APIError(status_code, apic_message='')[source]¶
Bases:
NiwakiErrorThe APIC responded with an HTTP error status (4xx or 5xx).
- status_code¶
HTTP status code returned by the APIC.
- apic_message¶
Error text extracted from the APIC payload, if available.
- exception niwaki.exceptions.AmbiguousBindError[source]¶
Bases:
DesignErrorNo unambiguous Rs class exists for a
bindedge.Neither
REFERENCE_MAP[owner][target]nor the inverseREFERENCE_MAP[target][owner]resolves to a relationship class. Use.mo(RsClass, ...)to create the relationship explicitly.
- exception niwaki.exceptions.AuthError[source]¶
Bases:
NiwakiErrorBase class for APIC authentication errors.
Subclasses cover login failure, token refresh failure, and full session expiry.
- exception niwaki.exceptions.ConnectionError[source]¶
Bases:
TransportErrorThe APIC host is unreachable (DNS failure, TCP refused, interface down, etc.).
Wraps
httpx.ConnectErrorin non-TLS cases.Note
This name intentionally shadows the Python builtin
ConnectionError. Inside the SDK, useniwaki.exceptions.ConnectionError.
- exception niwaki.exceptions.DeserializationError[source]¶
Bases:
NiwakiErrorThe APIC payload cannot be parsed into a typed niwaki model.
Raised by the model layer when the response structure returned by the APIC does not match the expected Pydantic schema. This can happen if:
The APIC firmware version returned a field that the SDK schema does not recognise (forwards-compatibility issue).
A required field is missing from the APIC response (schema drift).
A field value has an unexpected type.
- args[]¶
Human-readable description including the class name and the Pydantic validation error.
Example:
try: tenant = session.get_mo("uni/tn-Prod", fvTenant) except DeserializationError as exc: logger.error("Schema mismatch for fvTenant: %s", exc)
- exception niwaki.exceptions.DesignError[source]¶
Bases:
NiwakiErrorBase class for all design-DSL errors.
- exception niwaki.exceptions.DuplicateDeclarationError[source]¶
Bases:
DesignErrorThe same object (class + naming) was declared twice in a design.
- exception niwaki.exceptions.ForbiddenError(status_code, apic_message='')[source]¶
Bases:
APIErrorThe APIC returned HTTP 403 — the authenticated user lacks sufficient privileges.
Difference from
UnauthorizedError: - 401 = not authenticated (invalid token). - 403 = authenticated but not authorised on this resource.
- exception niwaki.exceptions.LoginError[source]¶
Bases:
AuthErrorThe APIC rejected the credentials during login.
Raised when POST
/api/aaaLogin.jsonreturns a non-200 status or the response contains an APIC error message (wrong password, locked account, etc.).- args[]¶
Error message including the HTTP status and APIC text.
- exception niwaki.exceptions.MultipleResultsError[source]¶
Bases:
NiwakiErrorA query that required exactly one object matched more than one.
Raised by
one()/one()when the result set holds two or more objects. Narrow the query, or usefirst()/fetch()when several matches are expected.
- exception niwaki.exceptions.NiwakiError[source]¶
Bases:
ExceptionBase class for all niwaki SDK errors.
- exception niwaki.exceptions.NoResultError[source]¶
Bases:
NiwakiErrorA query that required exactly one object matched none.
Raised by
one()/one()when the result set is empty. Usefirst()when no match is an acceptable outcome.
- exception niwaki.exceptions.NotFoundError(status_code, apic_message='')[source]¶
Bases:
APIErrorThe APIC returned HTTP 404 — the requested MO does not exist.
The DN or API path is invalid, or the object has been deleted.
- exception niwaki.exceptions.ServerError(status_code, apic_message='')[source]¶
Bases:
APIErrorThe APIC returned a 5xx error — server-side APIC error.
These errors are considered transient and may be retried. If they persist after all retry attempts, this exception is raised.
- exception niwaki.exceptions.SessionExpiredError[source]¶
Bases:
AuthErrorThe session is fully expired: both refresh and re-login failed.
Raised when the token has expired and no renewal attempt succeeded. The caller must create a new
ApicSession.- args[]¶
Message describing the reason for expiry.
- exception niwaki.exceptions.StagedPushError(report, failures, not_run)[source]¶
Bases:
DesignErrorA
push(mode="staged")partially succeeded.Carries the partial
PushReport(the DNs actually written, in execution order) and the failures as plain(dn, exception)pairs — no engine internals leak into the public surface.- Parameters:
report (PushReport) – Partial push report —
report.dnsare the DNs written, including every independent branch that succeeded around a failure.failures (list[tuple[str, Exception]]) –
(dn, exception)for every operation that failed.not_run (list[str]) – DNs never attempted because an ancestor object failed — pushing them without their parent would only 404. A failure isolates its own subtree; sibling branches are still written.
Example:
from niwaki.exceptions import StagedPushError try: config.push(aci, mode="staged") except StagedPushError as exc: print(f"written : {exc.report.dns}") print(f"failed : {[dn for dn, _ in exc.failures]}") print(f"skipped : {exc.not_run}")
- exception niwaki.exceptions.StatsClassNotSubscribableError[source]¶
Bases:
SubscriptionErrorA subscription targeted a class the APIC can never push for.
Raised before any network I/O. Stats classes (
isStatin the read catalogue) bypass the APIC’s internal event manager entirely — Cisco’s own documentation states updates are “too frequent and not scalable” to route through it — so a subscription would be silently accepted and never push anything. This is an architectural fact, unlikeisObservable(seeis_observable), which was empirically found not to gate subscribability and is therefore never enforced here.
- exception niwaki.exceptions.SubscribeRejectedError(status_code, apic_message='')[source]¶
Bases:
SubscriptionError,APIErrorThe APIC rejected a
subscription=yesrequest.Multiply inherits
APIErrorfor the familiarstatus_code/apic_messageattributes (precedent:UnknownMakerError(DesignError, AttributeError)), so a caller can inspect the HTTP status while still catching every subscription failure with a singleexcept SubscriptionError.
- exception niwaki.exceptions.SubscriptionError[source]¶
Bases:
NiwakiErrorBase class for every object-subscription failure.
- exception niwaki.exceptions.SubscriptionLostError(message, *, reason=SubscriptionLostReason.RECONNECT_EXHAUSTED)[source]¶
Bases:
SubscriptionErrorA subscription could not be recovered.
Raised out of the subscription’s iterator (
__next__/__anext__), terminating it. This is the one truly fatal outcome — everything short of it (a missed refresh, a reconnect that did succeed) is represented as data in the event stream instead, because there is something left to reconcile toward. Seereasonfor which recovery path was exhausted.- reason¶
Which recovery path failed — see
SubscriptionLostReason.
- class niwaki.exceptions.SubscriptionLostReason(*values)[source]¶
Bases:
StrEnumWhich recovery path was exhausted before
SubscriptionLostErrorwas raised.Distinguishes three distinct fatal paths that would otherwise be indistinguishable from the error message alone:
RECONNECT_EXHAUSTED: the shared WebSocket itself could not be reconnected — every tracked subscription on the socket receives this.RESUBSCRIBE_FAILED: the socket reconnected, but the APIC rejected this subscription’s resubscribe — sibling subscriptions on the same socket may still be fine.REFRESH_ESCALATION: two consecutive scheduled refreshes failed, and the recovery resubscribe attempted for this subscription alone also failed — the socket connection itself was never affected.
- exception niwaki.exceptions.TLSError[source]¶
Bases:
TransportErrorTLS/SSL error when connecting to the APIC.
Common causes: - Self-signed certificate with
verify_ssl=True(default). - Expired certificate or incorrect domain name. - Incomplete CA chain.Quick fix (not recommended in production):
verify_ssl=False.
- exception niwaki.exceptions.TimeoutError[source]¶
Bases:
TransportErrorA request to the APIC exceeded the configured timeout.
Wraps
httpx.TimeoutException(covers connect timeout, read timeout, write timeout, and pool timeout).Note
This name intentionally shadows the Python builtin
TimeoutError.
- exception niwaki.exceptions.TokenRefreshError[source]¶
Bases:
AuthErrorToken refresh via
/api/aaaRefresh.jsonfailed.The session will automatically attempt a full re-login as fallback. This exception should not reach the caller in the normal case; it surfaces only if the fallback itself is disabled or fails.
- exception niwaki.exceptions.TransportError[source]¶
Bases:
NiwakiErrorBase class for network/transport layer errors.
All subclasses wrap corresponding
httpxexceptions.
- exception niwaki.exceptions.UnauthorizedError(status_code, apic_message='')[source]¶
Bases:
APIErrorThe APIC returned HTTP 401 — the session token is invalid or expired server-side.
Raised only if the 401 persists after automatic re-authentication, indicating that the credentials themselves were revoked or that the resource is not accessible to this user.
- exception niwaki.exceptions.UnknownMakerError[source]¶
Bases:
DesignError,AttributeErrorA maker name resolved at no level of the cursor’s ancestor path.
Also an
AttributeErrorso thathasattrand attribute protocols keep working on cursors.
- exception niwaki.exceptions.UnresolvedReferenceError[source]¶
Bases:
DesignErrorA
bind/provide/consumetarget is not declared in the design.Raised during closed-world validation at push time. The message includes the declared instances of the target class and a did-you-mean suggestion.