Errors

Nothing in pycosmicsdk returns a status code. Every failure is an exception, and every exception derives from CosmicError, which carries a status_code and an optional operation label naming the call site.

Exception
└── CosmicError
    ├── ValidationError            arguments rejected before any native call
    ├── CapabilityError            protocol the device does not have
    ├── DeviceNotFoundError        no adapter matched the open criteria
    ├── UnsupportedFirmwareError   firmware too old for this package to speak to
    ├── DisconnectError            device gone mid-operation
    ├── AdapterNotAnsweringError   handle live, adapter stopped replying
    ├── CosmicTimeoutError         also a builtins.TimeoutError
    ├── ProtocolError              protocol-level, not firmware state
    ├── CosmicSDKLibraryNotFound   bundled shared library not located
    ├── CosmicSDKVersionError      loaded library reports an incompatible version
    ├── CosmicInternalError        a violated SDK invariant -- a bug in this SDK
    └── FirmwareError              reported by device firmware, via a status code
        ├── SystemFirmwareError    0x01xx band (voltage, reset, ...)
        ├── I2cError               0x02xx band
        ├── I2cDutyCycleRefusedError  set_duty_cycle's FW_INVALID_PARAMETER, with the settings kept
        ├── SpiError               0x03xx band — SPI target mode only, see below
        ├── UartError              0x04xx band
        ├── GpioError              0x05xx band
        ├── I3cError               0x06xx band
        └── DebugError             0x1Dxx/0x1Exx — a DebugProbe's target flash and debug session
            └── TargetFlashVerifyError  TargetFlash.write's readback mismatch, with the address

The bands are upstream’s own: a firmware result code carries its GROUP_* in the high byte (submodules/CosmicSDK/include/definitions.h). Generic firmware codes (0x0001–0x000E) sit below every band, and anything from 0x0700 up other than 0x1Exx sits above them; both fall through to FirmwareError itself. 0x1Exx are the debug probe’s host-side debug codes (DebugProbeDebugCodes.h), raised as DebugError with the code’s name in the message.

Which one to catch

CosmicError is the blanket catch — every example script uses it at the top level.

FirmwareError is the right granularity for “the device rejected this”. The per-protocol subclasses are narrower than their names suggest, because a status code lands in a protocol band only if firmware put it there:

  • A rejected configuration is normally the generic FW_INVALID_PARAMETER, and an uninitialised interface FW_INTERFACE_NOT_INITIALIZED — both below every band, so both plain FirmwareError.

  • A rejected voltage is in the 0x01xx system band, so SystemFirmwareError, whichever interface asked for it.

  • UartError covers exactly one upstream code, FW_UART_IN_VCOM_PORT_MODE.

  • I2cError’s band, by contrast, is well populated — address NACK, arbitration lost, SCL held low.

ValidationError is raised Python-side, before any USB traffic: bad argument ranges and field widths, over-the-maximum payloads, the GPIO direction guard, the HDR-DDR length constraints, I3C target memory bounds.

CapabilityError is also raised Python-side, before any USB traffic — see the section below, which is the one thing on this page most likely to catch a reader out.

CosmicTimeoutError multi-inherits TimeoutError, so except TimeoutError: catches it. The Cosmic prefix keeps it from shadowing the built-in after a from pycosmicsdk import *.

AdapterNotAnsweringError is this SDK refusing to send, after three consecutive timeouts on one handle with nothing answering in between. It is not a TimeoutError — see the section below for why that is deliberate.

examples/blocking_api/i2c/error_handling.py provokes one failure per layer and prints which exception each produces.

Capability refusals arrive before the wire

CapabilityError means this adapter cannot do this, and nothing was sent. It covers two kinds of limit — a protocol the model does not have at all (Device.i3c() on a Pulsar, an I2cBus the model does not carry), and a narrower limit that a guard checks in front of an otherwise-available call:

Refused call

Because

configure, set_pull_up

the hardware revision cannot reconfigure a live I2C interface

initialize, configure, set_pull_up

this model’s firmware has no table row for the requested I2cPullUp

configure_interrupt

the hardware revision cannot arm an interrupt on that pin

Any of the three protocols’ transport= arguments with BULK — write / read, write / read, sdr_write / sdr_read among them

the device or the host declined to negotiate the bulk transport. I2C and I3C refuse exactly as SPI does, each through its own guard: BULK is a demand, and AUTO is the argument that never raises this

SpiTarget.initialize, bring_up, and Device.spi_target()

this hardware revision cannot receive an incoming chip select — a rev-B Supernova, and only that one revision

I2cTarget.initialize and SpiTarget.initialize, and their bring_ups and asyncio twins

the target’s memory arena travels only over the bulk plane and has no HID route, so an unreachable plane is refused at arming rather than two calls later. Waived with require_arena_access=False

set_usb_config

this model fits no transceiver for the requested CdcMode — TERMINAL is Supernova-only, RS485 and CANFD are Pulsar-only

Two consequences, and both have bitten this repository’s own examples:

It is not a FirmwareError. CapabilityError derives straight from CosmicError, so a handler written as except FirmwareError — the natural shape for “the device rejected this” — does not catch it. Give it its own clause.

Do not filter it on status_code. Because nothing reached the device, there is no firmware rejection code to carry; the guards raise StatusCode.SDK_ERROR_WRONG_REQUEST. A handler that catches CapabilityError and then re-raises unless the code is on some allow-list re-raises every capability refusal. That is why the pattern below puts the two on separate clauses and filters only the firmware one:

from pycosmicsdk import CapabilityError, FirmwareError, StatusCode

try:
    i2c.configure(frequency_hz=400_000, pull_up=I2cPullUp.OHM_330)
except CapabilityError:
    # Refused before the wire, so this is by definition the recoverable case:
    # the bus is still running exactly as initialize() left it. No status
    # filter -- the code is SDK_ERROR_WRONG_REQUEST, not a firmware code.
    settings_applied = False
except FirmwareError as exc:
    # Here the code *is* what distinguishes a rejected config from a fault.
    if exc.status_code is not StatusCode.FW_FEATURE_NOT_SUPPORTED_BY_HARDWARE:
        raise
    settings_applied = False

examples/helpers.py (i2c_bring_up, i2c_set_pull_up, and their asyncio twins) is the bench-verified version of exactly this, and every I2C example goes through it.

Note

StatusCode.SDK_ERROR_WRONG_REQUEST is the SDK’s generic “this request was never sent” code and it is carried by four different classes: a ValidationError (a bad argument), a CapabilityError (a model or revision limit), a ProtocolError (a request CosmicSDK itself rejected as malformed, and that this SDK did not pre-empt — a sub-address longer than four bytes is the live case) and CosmicInternalError. The class carries the meaning; the code does not. Branch on the class.

Upstream also rejects an I3C PID that is not six bytes and an out-of-range target-memory address with the same code, but neither reaches it: this SDK checks both Python-side first, so they arrive as ValidationError.

Better than catching: ask first. DeviceCapabilities answers all five limits with no USB traffic — capabilities.i2c_runtime_reconfigurable, capabilities.supports_i2c_pull_up(pull_up), capabilities.supports_gpio_interrupt(pin), capabilities.spi_target_capable and capabilities.supports_spi_bulk() / capabilities.supports_i3c_bulk(). See Capabilities you can ask about in advance.

Refusals fail open

A CapabilityError tells you one of three things, and it is worth knowing which before you go looking for a cable fault:

You have the wrong device. A protocol or bus the model does not carry — Device.i3c() on a Pulsar, I2cBus.B on a Supernova, a CdcMode whose transceiver this board does not fit, an I2cPullUp with no row in this model’s firmware table. No revision of that model changes the answer and no argument avoids it; the fix is a different adapter, or a different value.

You have the wrong revision. A limit of the board, not the model: reconfiguring a live I2C interface, or arming a GPIO interrupt on the one pin whose revision cannot. The same model at another revision does it fine. The message names the revision it read, so SUPERNOVA HW-B in the text is the thing to check.

You have the wrong expectation. SpiTransport.BULK is a demand, not a preference. SpiTransport.AUTO asks for the best available transport and never raises this.

Important

An unknown answer means “attempt it”, never “refuse it”. This SDK carries the model and revision tables in Python because CosmicSDK exposes no capabilities query, and a table can be out of date in two directions. Refusing an operation that would have worked is the worse failure — a user cannot work around it — so every guard is arranged so that ignorance falls through to the device:

  • A model firmware does not apply the limit to is not gated at all. The live-reconfigure check exists only in the Supernova firmware build, so i2c_runtime_reconfigurable is True on every Pulsar whatever its hw_version says, and the guard in front of configure never fires there.

  • A DeviceModel this release has never been taught reaches no guard either, and the CdcMode check has no entry for it and passes every mode through.

  • An hw_version string that does not parse as a revision — an empty field, a firmware that starts reporting a semver, a shape nobody anticipated — is attempted rather than refused. The one gate written as an equality (i2c_runtime_reconfigurable, mirroring firmware’s own hwVersion != 'C') routes both that case and an ungated model around the equality rather than through it, because inverting a table is exactly where fail-open gets lost.

  • The GPIO interrupt table lists the pin/revision pairs known to be broken, so a pair absent from it is armed. That is why it holds a single cell — Supernova Rev B, PIN_3 — rather than an enumeration of what works.

The two pull-up tables are the exception, and read the other way round: they enumerate the values firmware accepts, per model, so a value absent from one is refused here. They can be that strict because firmware’s own table is a closed per-model set — a value it does not name has no resistance to program, so there is nothing to fail open to.

The cost of failing open is that a limit this SDK has not been taught still reaches the device and comes back as a firmware code — typically FW_FEATURE_NOT_SUPPORTED_BY_HARDWARE or FW_INVALID_PARAMETER, as a plain FirmwareError. That is the deliberate trade: a loud, late, correctly-attributed failure in preference to an early refusal that might have been wrong.

Whole protocols are the one thing that does not fail open, and it is worth knowing before you meet it. protocols and i2c_buses are enumerated positively per known model, so an adapter whose model this release does not recognise reports both as empty and every interface accessor — Device.i2c(), spi, uart, gpio, i3c — raises CapabilityError. The handle still opens and info still reports what the adapter said about itself, which is the point: you can identify an unrecognised unit and file a report, but you cannot drive it. If a supported adapter ever lands here, the model marker is what to look at first — it comes from the USB product id, not from a product string.

Note

SpiError has exactly one source: SPI target mode. Both status translators map the 0x03xx firmware band to it, and all seven codes in that band are target-mode ones — FW_SPI_ROLE_CONFLICT, FW_SPI_TARGET_STAGING_UNAVAILABLE, FW_SPI_TARGET_SURPASSED_MEMORY_SIZE, FW_SPI_TARGET_PAYLOAD_TRANSFER_FAILED, FW_SPI_TARGET_WRONG_MODEL, FW_SPI_TARGET_INVALID_CONFIG and FW_SPI_TARGET_REGION_TABLE_FULL. So a program that never calls Device.spi_target() will never see one, and controller-side SPI failures still arrive as FirmwareError (generic codes) or SystemFirmwareError (voltage). The SPI guide has the full per-failure table.

What this note said until 2026-09-05. It was a warning headed “SpiError is unreachable today — do not rely on catching it”, and argued that CosmicSDK’s definitions.h declared no FW_SPI_* status code at all, so the band was empty upstream and nothing reached the class. That was a true statement about an older submodule pin. The pinned definitions.h now declares the seven codes above and _status_maps.py maps every one of them to SpiError, so the advice it gave — catch FirmwareError instead — is now right for controller code only.

Note

CosmicInternalError — a violated internal invariant, an SDK bug rather than user error — is re-exported at package level:

from pycosmicsdk import CosmicInternalError

It was previously the only one of the eighteen names in pycosmicsdk.errors that the top-level package did not re-export, which for a raisable class was an oversight rather than a decision. It is now in pycosmicsdk.__all__, so from pycosmicsdk import * brings it in and it needs no import from the submodule.

It has one raise site — transaction-id exhaustion in the async engine, which can only happen if the SDK leaks pending entries — so an application that catches CosmicError already covers it, and one that catches it specifically is reporting a bug in this SDK rather than handling a device condition.

AdapterNotAnsweringError means this SDK stopped sending

AdapterNotAnsweringError is the only class on this page that is about the SDK’s own conduct rather than about your arguments, your device’s answer, or a message that did not parse. It says: three commands in a row on this handle timed out with no reply in between, so nothing more will be sent on it. No command was issued for the call that raised it.

It exists because continuing is not neutral. Backlog ticket 72 records a bench adapter driven through several handle cycles of timed-out commands, each one absorbed and followed by another, which ended up enumerating over USB-HID while refusing every open for more than 270 seconds — a state a physical unplug/replug was the only way out of, because no handle could be opened to send anything on, a reset included. On the firmware side the queues that back up are a handful of entries deep and every enqueue waits forever rather than failing, so a run of unanswered commands is what walks a device into it.

Three, not one. A single timeout is a normal, documented thing on real hardware and its shape is untouched here: it is still a CosmicTimeoutError, and so are the second and third. The guard changes nothing about a command it issued — only the command after the third refusal-free timeout is declined. Anything that answers, including a firmware rejection, resets the count: an empty I2C bus reporting FW_I2C_BUS_WITH_NO_TARGETS_CONNECTED in five milliseconds is a healthy adapter.

Both surfaces, one rule. Device and AsyncDevice count identically — same limit of three, same definition of an answer, same refusal — because they share the count. An await reaches a wedged adapter exactly as a call does. Two asyncio details follow from commands being able to overlap there: concurrent awaits that all time out each count, so a gather of four unanswered commands trips the guard as surely as four sequential ones; and a command you cancel yourself counts for nothing in either direction, because a cancellation says nothing about whether the adapter would have replied.

What is exempt. Operations that cross no wire — Device.get_version and Device.subscribe, with their async twins — are neither refused on a tripped handle nor treated as answers on a live one, so a diagnostic loop cannot silently disarm the guard and a post-mortem can still read the handle, and start watching it, after it trips. Registering a subscription installs a host-side callback and sends nothing. Everything that can reach the wire is refused once the count is reached, including calls that would have sent nothing this time: the guard is about the handle, not the command.

Only an issued command counts, in either direction. A call that takes the handle and sends nothing is not an answer, and does not reset the run. That covers the calls a poll loop is built out of — I2cTarget.drain_events, wait_for_event, Uart.receive, the max_transfer_bytes and transport reads — none of which reach the adapter at all. Interleaving one between every command therefore has no effect on the count, which is what makes the guard reach the callers most likely to need it. Their own timeouts are not evidence either: Uart.receive timing out means the peer sent nothing, not that the adapter stopped answering. This is separate from the exemption above, which is about the refusal: once the count is reached these calls are declined like any other.

Catching it. It derives from CosmicError and deliberately from neither CosmicTimeoutError nor FirmwareError. except TimeoutError: will not catch it, which is the point: retrying on a timeout is the behaviour it exists to interrupt, and a handler that swallowed it as one more timeout would keep the loop running.

Recovering. The count is per handle. A new open or open starts a fresh one, and that the count is not keyed to the adapter’s serial is deliberate: such a latch would outlive the physical replug that fixes the worst case. Whether the adapter answers on that new handle is a property of the adapter.

If it does answer on the new handle, the SDK has one more lever, and this page said until 2026-09-05 that it had none: reboot with RUNTIME. A runtime reset clears latched firmware interface state — measured on a Pulsar, it cleared a persistent I2C controller role on both buses — and the adapter was openable again 0.825 s later. That is one observation on one adapter, so poll list_devices rather than sleeping a fixed interval, and note that it does not clear the bus VTARG setpoint.

A replug is what remains for the case where the reset is not dispatched at all. Ticket 72’s state is exactly that: a stranded protocol manager blocks the USB receive decoder, after which no command of any group is decoded, SYS included — so the reset request never reaches the code that would execute it. Do not read “a reset clears latched state” as “a reset recovers a wedge”; that has not been tested, and the one relevant observation says the opposite for a device in that state.

Warning

This guard cannot un-wedge a device, and it is not a proof against wedging one. It stops this SDK adding to a run of unanswered commands; it arrives too late for a device that has already stopped answering, and firmware has at least one path to a mute HID interface that a single abandoned transfer can reach, which no host-side count can prevent. Treat it as a diagnosis worth acting on, not as a guarantee.

ProtocolError means the answer did not parse

ProtocolError is the one class on this page that is about neither your arguments nor a firmware rejection. It says: the SDK and the device did not agree on the shape of a message. Nothing in it is a firmware status code, so there is no FW_* value to branch on and no bus condition to retry through.

Both status translators map exactly three SDK-level codes to it — SDK_ERROR_WRONG_REQUEST, SDK_ERROR_WRONG_RESPONSE and SDK_ERROR_UNEXPECTED_RESPONSE — which is two distinct situations:

The request was never formed. CosmicSDK refused to build the frame, so nothing was sent. The live case is a subaddress longer than four bytes on any I2C or I3C read/write; each of those methods documents ProtocolError in its Raises: block for exactly that.

The response could not be decoded. The adapter answered, and the reply was too short to carry the fields it should have, or carried a value this release does not name. get_usb_config raises it for a CdcMode newer than this SDK; get_analog_measurements raises it for a reply that does not carry all six rails; the GPIO logic-level read, the CCC decoders and the length-prefixed protocol reads each have the same bounds check in front of them, because upstream reads several of these blocks by reinterpret_cast with no length check at all.

Important

Firmware that predates a command reports itself as a ProtocolError, not as an unsupported-command FirmwareError. A firmware error response carries the six-byte generic header and nothing else, so from the decoder’s point of view it is simply a reply too short to parse. This is documented behaviour on get_usb_config and get_analog_measurements, whose docstrings both say so — a ProtocolError from either on an older adapter most likely means update the firmware, not retry.

So a handler for it does not recover; it reports. What is worth printing alongside is which versions were in play, since a mismatch between them is the usual cause:

import pycosmicsdk
from pycosmicsdk import Device, ProtocolError

with Device.open() as dev:
    try:
        config = dev.get_usb_config()
    except ProtocolError as exc:
        print(f"could not read the USB configuration: {exc}")
        print(f"  pycosmicsdk      : {pycosmicsdk.__version__}")
        print(f"  CosmicSDK library: {dev.get_version()}")
        print(f"  adapter firmware : {dev.info.fw_version}")
    else:
        print(config)

The two loader errors nothing raises yet

CosmicSDKLibraryNotFound and CosmicSDKVersionError are in the hierarchy above and in pycosmicsdk.__all__, and no code path in this SDK raises either of them. They are wired for the same reason SpiError is: the class should already exist if the condition ever becomes reachable.

The condition is not reachable today because there is nothing to load. The native library is statically linked into the compiled extension, so there is no shared library to locate on disk (Device.open() takes no lib_path, and there is no COSMICSDK_LIB_PATH environment variable) and no separately installed version to check against. Both names are carried over from a superseded ctypes design in which the library was found and version-checked at run time.

What you can actually meet at import time is Python’s own ImportError, from import pycosmicsdk failing to load the extension module — a broken or mismatched wheel, or a source checkout that was never built. That is not a CosmicError and no except CosmicError will see it. Do not write a handler for these two expecting to catch a bad install.

Reference

class pycosmicsdk.CosmicError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: Exception

Base class for every error raised by pycosmicsdk.

eq=False ensures that exceptions are only considered equal if they are the same object, which is the intended behavior for exceptions.

status_code is normally a StatusCode enum value but may also be a plain int for firmware codes the SDK has not yet mapped — the typed formatter falls back to a hex digest in that case so the error string remains human-readable.

status_code

The originating status code; a StatusCode enum value, or a plain int for firmware codes the SDK has not yet mapped.

Type:

pycosmicsdk._cpp._pycosmicsdk_cpp.StatusCode | int

operation

Optional label identifying the call site, prefixed to the default error string.

Type:

str | None

message

Optional explicit message; when empty, a message is derived from operation and status_code.

Type:

str

class pycosmicsdk.ValidationError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when arguments are rejected before any CosmicSDK call is made.

class pycosmicsdk.CapabilityError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when a call targets a protocol the device does not support.

class pycosmicsdk.DeviceNotFoundError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when no device matching the connect criteria is enumerated.

class pycosmicsdk.UnsupportedFirmwareError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when the adapter runs firmware this package cannot speak to.

CosmicSDK frames every request with the firmware 4.0 USB transfer protocol header; firmware 3.x writes raw commands with none, so nothing sent reaches a 3.x adapter and the first command spends the whole timeout. That timeout is what a caller used to receive, and it reads as a broken adapter rather than as an adapter this package cannot drive.

Deliberately not a CosmicTimeoutError: a caller looping on a timeout retries, and against this adapter that loop never ends. Nothing about the device will change until its firmware does.

class pycosmicsdk.DisconnectError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when the device is no longer reachable mid-operation.

class pycosmicsdk.AdapterNotAnsweringError(status_code: StatusCode | int, operation: str | None = None, message: str = '', consecutive_timeouts: int = 0, waited_s: float = 0.0)

Bases: CosmicError

Raised when this handle refuses to issue another command, and why.

Not a device answer and not a timeout: it is this SDK declining to send anything more on a handle whose last several commands all timed out. It derives from CosmicError and deliberately not from CosmicTimeoutError, because the behaviour it exists to stop is a caller looping on except TimeoutError: and retrying. The message names the recovery steps, in the order worth trying them.

consecutive_timeouts

How many commands in a row timed out.

Type:

int

waited_s

Wall time those timed-out commands spent, in seconds.

Type:

float

class pycosmicsdk.CosmicTimeoutError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError, TimeoutError

Raised on SDK_ERROR_TIMEOUT.

Multi-inherits builtins.TimeoutError so that callers can write except TimeoutError: and still catch this. The Cosmic prefix keeps it from shadowing the built-in if a user does from pycosmicsdk import *.

class pycosmicsdk.ProtocolError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised on protocol-level errors not attributable to firmware state.

class pycosmicsdk.CosmicSDKLibraryNotFound(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when the bundled CosmicSDK shared library cannot be located.

class pycosmicsdk.CosmicSDKVersionError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when the loaded CosmicSDK library reports an incompatible version.

class pycosmicsdk.CosmicInternalError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Raised when an internal SDK invariant is violated (an SDK bug, not user error).

class pycosmicsdk.FirmwareError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: CosmicError

Base for errors reported by device firmware via a status code.

class pycosmicsdk.I2cError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Firmware error raised on the I2C bus.

class pycosmicsdk.I2cDutyCycleRefusedError(status_code: StatusCode | int, operation: str | None = None, message: str = '', frequency_hz: int | None = None, high_pct: int | None = None)

Bases: FirmwareError

Raised when firmware refuses I2cController.set_duty_cycle’s ratio.

status_code is FW_INVALID_PARAMETER. The refusal reply still carries the settings the bus keeps, so they are here rather than lost: a caller learns what the bus runs at without a second command. A FirmwareError, not an I2cError, because the code is a generic one.

frequency_hz

SCL frequency in effect after the refusal, in Hz; None if the reply did not carry it.

Type:

int | None

high_pct

High share in effect after the refusal (0 = default timing); None if the reply did not carry it.

Type:

int | None

class pycosmicsdk.UartError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Firmware error raised on the UART interface.

class pycosmicsdk.I3cError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Firmware error raised on the I3C bus.

class pycosmicsdk.SpiError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Firmware error raised on the SPI interface.

class pycosmicsdk.GpioError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Firmware error raised on a GPIO line.

class pycosmicsdk.SystemFirmwareError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Firmware error raised by system-level commands (voltage, reset, …).

class pycosmicsdk.DebugError(status_code: StatusCode | int, operation: str | None = None, message: str = '')

Bases: FirmwareError

Error from a debug probe’s debug session (attach, halt, memory, breakpoints).

class pycosmicsdk.TargetFlashVerifyError(status_code: StatusCode | int, operation: str | None = None, message: str = '', first_mismatch: int | None = None)

Bases: DebugError

Raised when TargetFlash.write(..., verify=True) reads back different bytes.

status_code is DEBUGPROBE_TFLASH_VERIFY_MISMATCH (0x1D07). The flash was erased and programmed; only the readback disagreed.

first_mismatch

First differing address; None if the report lacks it.

Type:

int | None