Skip to content

Exceptions

Hierarchy

PiKVMError
├── APIError
│   ├── AuthError
│   ├── BusyError
│   ├── UnavailableError
│   ├── RedirectError
│   └── ResponseError
├── ConfigurationError
├── ConnectError
├── ConnectionTimeoutError
├── WebRTCError
└── WebSocketError

Reference

PiKVMError

Base exception for all aiopikvm errors.

Source code in src/aiopikvm/_exceptions.py
class PiKVMError(Exception):
    """Base exception for all aiopikvm errors."""

APIError

Bases: PiKVMError

PiKVM refused the request or answered with something unusable.

Attributes:

Name Type Description
status_code

HTTP status code. 0 when there was no single status to report: an error kvmd put in the body of an HTTP 200, or a redirect loop the client gave up on.

error

kvmd's exception class name, e.g. "AtxIsBusyError". Empty when the response carried no kvmd error block.

error_msg

kvmd's human-readable message, e.g. "Performing another ATX operation, please try again later". Empty when the response carried no kvmd error block.

Source code in src/aiopikvm/_exceptions.py
class APIError(PiKVMError):
    """PiKVM refused the request or answered with something unusable.

    Attributes:
        status_code: HTTP status code. ``0`` when there was no single status
            to report: an error kvmd put in the body of an HTTP 200, or a
            redirect loop the client gave up on.
        error: kvmd's exception class name, e.g. ``"AtxIsBusyError"``. Empty
            when the response carried no kvmd error block.
        error_msg: kvmd's human-readable message, e.g. ``"Performing another
            ATX operation, please try again later"``. Empty when the response
            carried no kvmd error block.
    """

    def __init__(
        self,
        message: str,
        status_code: int = 0,
        *,
        error: str = "",
        error_msg: str = "",
    ) -> None:
        super().__init__(message)
        self.status_code = status_code
        self.error = error
        self.error_msg = error_msg

AuthError

Bases: APIError

Authentication failed (HTTP 401/403).

Source code in src/aiopikvm/_exceptions.py
class AuthError(APIError):
    """Authentication failed (HTTP 401/403)."""

BusyError

Bases: APIError

PiKVM is busy with another operation (HTTP 409).

Raised by ATX, MSD and GPIO calls while an earlier operation is still running; the same call usually succeeds once it finishes. error names the subsystem's own kvmd class, such as "AtxIsBusyError".

Source code in src/aiopikvm/_exceptions.py
class BusyError(APIError):
    """PiKVM is busy with another operation (HTTP 409).

    Raised by ATX, MSD and GPIO calls while an earlier operation is still
    running; the same call usually succeeds once it finishes. ``error`` names
    the subsystem's own kvmd class, such as ``"AtxIsBusyError"``.
    """

UnavailableError

Bases: APIError

The subsystem is offline (HTTP 503).

Raised for a subsystem that cannot serve the request right now — an MSD that has not finished setting up, or a snapshot while the video source has no signal. A subsystem switched off in the kvmd config answers HTTP 400 instead, so that arrives as a plain APIError whose error names the reason, e.g. "AtxDisabledError".

Source code in src/aiopikvm/_exceptions.py
class UnavailableError(APIError):
    """The subsystem is offline (HTTP 503).

    Raised for a subsystem that cannot serve the request right now — an MSD
    that has not finished setting up, or a snapshot while the video source has
    no signal. A subsystem switched off in the kvmd config answers HTTP 400
    instead, so that arrives as a plain [`APIError`][aiopikvm.APIError] whose
    ``error`` names the reason, e.g. ``"AtxDisabledError"``.
    """

RedirectError

Bases: APIError

A redirect the client would not or could not follow.

kvmd redirects doubled and trailing slashes, and PiKVM's nginx redirects http:// to https://. Following those silently would resend the credentials to wherever the redirect points, so the client reports them instead unless it was created with follow_redirects=True, over both HTTP and the WebSocket.

With following turned on this also reports a redirect loop, which no setting can resolve. That is the one case where status_code is 0 rather than the 3xx: the client gave up across several responses instead of refusing one.

Source code in src/aiopikvm/_exceptions.py
class RedirectError(APIError):
    """A redirect the client would not or could not follow.

    kvmd redirects doubled and trailing slashes, and PiKVM's nginx redirects
    ``http://`` to ``https://``. Following those silently would resend the
    credentials to wherever the redirect points, so the client reports them
    instead unless it was created with ``follow_redirects=True``, over both
    HTTP and the WebSocket.

    With following turned on this also reports a redirect *loop*, which no
    setting can resolve. That is the one case where ``status_code`` is ``0``
    rather than the 3xx: the client gave up across several responses instead
    of refusing one.
    """

ResponseError

Bases: APIError

PiKVM answered with a payload the client could not parse.

Either the body was not the JSON envelope the API is documented to return, or it did not match the model describing that endpoint — which usually means a kvmd version this release does not know about yet.

Source code in src/aiopikvm/_exceptions.py
class ResponseError(APIError):
    """PiKVM answered with a payload the client could not parse.

    Either the body was not the JSON envelope the API is documented to
    return, or it did not match the model describing that endpoint — which
    usually means a kvmd version this release does not know about yet.
    """

ConfigurationError

Bases: PiKVMError

The client cannot use what it was given.

Raised before anything reaches the device: a base URL without a usable scheme, credentials that cannot be put into HTTP headers, and arguments the API could not carry — a call with no parameters at all, or a value that kvmd's own encoding would silently mangle on the way in.

Source code in src/aiopikvm/_exceptions.py
class ConfigurationError(PiKVMError):
    """The client cannot use what it was given.

    Raised before anything reaches the device: a base URL without a usable
    scheme, credentials that cannot be put into HTTP headers, and arguments
    the API could not carry — a call with no parameters at all, or a value
    that kvmd's own encoding would silently mangle on the way in.
    """

ConnectError

Bases: PiKVMError

Failed to connect to PiKVM, or the connection broke mid-request.

Source code in src/aiopikvm/_exceptions.py
class ConnectError(PiKVMError):
    """Failed to connect to PiKVM, or the connection broke mid-request."""

ConnectionTimeoutError

Bases: PiKVMError

Request to PiKVM timed out.

Source code in src/aiopikvm/_exceptions.py
class ConnectionTimeoutError(PiKVMError):
    """Request to PiKVM timed out."""

WebRTCError

Bases: PiKVMError

A WebRTC failure, with no HTTP status to carry.

Once the upgrade is through, /janus/ws speaks Janus's own protocol rather than kvmd's, so a failure there has neither an HTTP status nor a kvmd error class to report. This carries Janus's numbering instead: a top-level error, where Janus itself refused — an unknown session, a handle that is gone — or a plugin error, where the request reached the ustreamer plugin and it said no. A negotiation that never completed and a session used while it is not open — before its async with block, or after it — report the same way, with no code to carry.

The upgrade itself is not this: kvmd's auth chain sits in front of Janus, so a refused handshake raises AuthError/APIError like any request, and the signalling socket failing raises WebSocketError.

Attributes:

Name Type Description
code

Janus's own error code, or the plugin's. 0 when the failure had no code — a negotiation that timed out, a session that was not open, or an answer whose shape this release does not recognise.

reason

The text Janus or the plugin sent beside that code. Empty when there was none.

Source code in src/aiopikvm/_exceptions.py
class WebRTCError(PiKVMError):
    """A WebRTC failure, with no HTTP status to carry.

    Once the upgrade is through, ``/janus/ws`` speaks Janus's own protocol
    rather than kvmd's, so a failure there has neither an HTTP status nor a
    kvmd error class to report. This carries Janus's numbering instead: a
    top-level error, where Janus itself refused — an unknown session, a
    handle that is gone — or a plugin error, where the request reached the
    ustreamer plugin and it said no. A negotiation that never completed and a
    session used while it is not open — before its ``async with`` block, or
    after it — report the same way, with no code to carry.

    The upgrade itself is not this: kvmd's auth chain sits in front of Janus,
    so a refused handshake raises ``AuthError``/``APIError`` like any
    request, and the signalling socket failing raises ``WebSocketError``.

    Attributes:
        code: Janus's own error code, or the plugin's. ``0`` when the failure
            had no code — a negotiation that timed out, a session that was
            not open, or an answer whose shape this release does not
            recognise.
        reason: The text Janus or the plugin sent beside that code. Empty when
            there was none.
    """

    def __init__(self, message: str, code: int = 0, *, reason: str = "") -> None:
        super().__init__(message)
        self.code = code
        self.reason = reason

WebSocketError

Bases: PiKVMError

WebSocket connection error.

Source code in src/aiopikvm/_exceptions.py
class WebSocketError(PiKVMError):
    """WebSocket connection error."""