Skip to content

Errors

Everything the client raises derives from MetranaQueryError, so one except covers the API:

from metrana.query import MetranaQueryError
try:
frame = client.fetch_float_series(runs, "loss")
except MetranaQueryError as err:
...
Exception Raised when
ConfigError Bad client-side configuration — no workspace, no project where one is needed, a malformed endpoint URL, an unreadable CA bundle.
TransportError Connection-level failure (DNS, TLS, refused) with retries exhausted — including at construction, when the endpoint is unreachable.
RpcError The server answered with a non-OK gRPC status after retries for transient codes. The message carries the status code and detail.
QueryTypeError An argument of the wrong type, or a builder used in a context that does not accept it.
QueryValueError An argument of the right type but an unusable value — an unknown enum spelling, an out-of-range bound, a selector the endpoint cannot express.

Every public method documents which of these it can raise, so help(client.fetch_runs) is authoritative for that method.

QueryTypeError derives from TypeError, and QueryValueError from ValueError:

try:
client.fetch_float_series_buckets(runs, "loss", x_mode="sideways")
except ValueError as err:
print(err)
# unknown x_mode 'sideways'; expected one of step/absolute_time/relative_time

So ordinary handlers keep working, and an enum coercion that would have raised a bare ValueError stays catchable the same way — while except MetranaQueryError still catches everything the SDK throws.

Some limits are deliberately errors rather than quiet truncation, because a silently short answer is the harder bug:

client.fetch_float_series(two_thousand_runs, "loss")
# QueryValueError: 2000 runs exceeds the 1000 a series fetch reads at once;
# narrow the run filter or set max_runs

A chart missing 1000 of its runs looks like a result. So the cap raises, and max_runs= is how you opt into a deliberate top-N.

An empty DataFrame, by contrast, is a legitimate answer: the filter matched nothing, or the series has no points in the range. Check frame.empty rather than catching.

Transient gRPC statuses are retried inside the client before any exception reaches you, so RpcError and TransportError mean the failure survived those retries. There is nothing to be gained by wrapping calls in your own immediate retry loop; treat them as real failures.