Skip to content

Errors

All public errors are metrana exception types — the underlying Rust engine’s own exception types never escape the API. They share a common base, so you can catch broadly or narrowly.

Exception Raised when
NoMetranaApiKeyError No api_key argument and METRANA_API_KEY is unset.
MetranaLoggerInitError The run fails to initialize — connection failure or init timeout.
MetranaRunAlreadyExistsError Under resume_strategy="never", the run exists and can’t be confirmed to belong to this job. The message carries the run path and (when reported) the existing run’s creation time.
MetranaOrchestrationIdMismatchError A different orchestration id — definitive proof of a different job launch. Raised either by the backend for an existing run, or, before any server contact, from a leftover disk spool of this run name on this node written by another launch — for init_mode="offline" that local check is the only one. Either way resume_strategy="allow" continues into it, and the message names the spool directory to delete when the run it belongs to is gone. Subclasses MetranaRunAlreadyExistsError, so existing handlers still catch it.
MetranaSpoolUnavailableError An explicitly configured disk spool cannot be used: its directory cannot be created or written. Subclasses MetranaLoggerInitError. The default spool is dropped with a warning instead, except under init_mode="offline", which cannot run without it.
MetranaUndeliverableSpoolError A spool of this run holds undelivered data this process cannot deliver — written by another machine, or by an SDK predating per-process spool directories. Starting would put the run’s steps above that data, and the service rejects a step below the last it accepted, so a later replay would drop it. Replay the directory named in the message, then start again — or give this process a disk= path it owns. Subclasses MetranaLoggerInitError.
import metrana
from metrana.utils.exceptions import MetranaRunAlreadyExistsError
try:
metrana.init(workspace_name="ws", project_name="proj", run_name="run-001")
except MetranaRunAlreadyExistsError as e:
# a different job already owns this run name
...
Exception Raised when
MetranaValidationError A logged metric or attribute is rejected as invalid (bad name, scale, points, step, episode, …). Raised synchronously from the log* call — validation is the enqueue boundary. Also raised for config-shape misuse of the spool, e.g. failover_to_spool() without init(disk=...).
MetranaEventQueueFullError The send queue is full and backpressure_strategy="raise".
Exception Raised when
MetranaSenderError Surfaces accumulated background sender errors — the generic logging-runtime failure. Under delivery_policy="all_or_crash", a logger stopped by a delivery failure surfaces this on the next log / flush / close.
MetranaTimeoutError A blocking call (e.g. flush) timed out before its data became durable. Distinct from loss — nothing was dropped; the data is still in flight, so a later flush/close (given time, ideally a disk spool) can still deliver it.
MetranaClosingError close / shutdown_logger deadline elapsed with data still not durable (neither acknowledged nor on the spool) — likely loss.
MetranaLoggerClosedError A call was made after the logger was closed.
Exception Raised when
MetranaNotInitializedError A log/lifecycle call before init().
MetranaProcessForkError A logging misuse across a fork() boundary (see Disk spool → fork).

Not everything the SDK reports is an exception. Conditions that don’t stop your run — a second init() call, a run that exited without close(), a rendering upload backlog, reference files skipped on download — are emitted as warnings under a dedicated category, MetranaWarning (a subclass of UserWarning) in metrana.utils.logging.

Rejected data is not in this group: an invalid metric name, scale, step, or episode raises MetranaValidationError rather than warning.

Because it’s its own category, you can control Metrana’s warnings without touching anyone else’s:

import warnings
from metrana.utils.logging import MetranaWarning
# quiet Metrana warnings (leaves other libraries' UserWarnings alone)
warnings.filterwarnings("ignore", category=MetranaWarning)
# or make them fatal, to catch logging misuse in CI
warnings.filterwarnings("error", category=MetranaWarning)

Escalating to "error" is the useful one in tests and CI: warnings about a missing close() or a duplicate init() become failures instead of scrolling past in the logs.

Some warnings are emitted once per key rather than on every occurrence, so a hot loop doesn’t flood your logs with the same message.

  • MetranaTimeoutError is benign. Treat it as “not yet durable”, not “lost” — re-flush or close later. Pair with a disk spool and generous timeouts for strong guarantees (see Lifecycle → sizing timeouts).
  • MetranaSenderError / MetranaClosingError mean likely loss. They are the loud failure the all_or_crash default is designed to produce instead of silently dropping data. A disk spool is what turns most of these into a transparent failover.
  • The exception types live in metrana.utils.exceptions if you want to import and catch specific ones.