Skip to content

Types & errors

Errors

All exceptions derive from SuperbAIError and carry a stable .code (ErrorCode) and human .hint — branch on .code.

Typed error hierarchy for the Superb AI SDK.

Every non-2xx API response raises a subclass of :class:APIError. The class tells you the HTTP status family; :attr:~APIError.code (an :class:ErrorCode) tells you the precise, stable error identity to branch on. The server's hint is embedded in str(exc) — it usually says exactly what to do next.

Retryable-by-SDK (automatic, see Client(max_retries=...)): 408, 429 (honors Retry-After), 5xx, and transport errors. Everything else raises immediately.

ErrorCode

Bases: StrEnum

Mirror of the server's stable error-code vocabulary (gate G3 keeps the two in lockstep both directions — a drifted member fails the build).

APIError

APIError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: Exception

Base for every API-raised error.

Attributes:

Name Type Description
status int

HTTP status code.

code

stable :class:ErrorCode (branch on this, not on messages).

message

human-readable server message.

hint

server-provided next-step advice (may be None).

request_id

server request id — include it when reporting issues.

details

structured extras (e.g. per-row validation errors), or None.

BadRequestError

BadRequestError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

400 — the request is well-formed JSON but semantically invalid (bad cursor, bad filter value, unsupported operation).

AuthenticationError

AuthenticationError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

401 — missing/invalid/expired credential. Check the API key (SUPERB_AI_API_KEY) or refresh the JWT.

ForbiddenError

ForbiddenError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

403 — authenticated but not allowed (workspace/project role too low).

NotFoundError

NotFoundError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

404 — the resource does not exist in this tenant/scope.

ConflictError

ConflictError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

409 — state conflict: name taken, edit-locked asset, idempotency-key replay with a different body, resource not ready, per-tenant job cap.

GoneError

GoneError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

410 — the resource existed but is permanently unavailable (EXPORT_EXPIRED / EXPORT_FAILED). Re-create the export.

PayloadTooLargeError

PayloadTooLargeError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

413 — over a hard cap (sync batch > 1000, body too large, asset too big). The message names the async/bulk alternative to use.

UnprocessableError

UnprocessableError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

422 — validation failed. details carries per-field/row errors.

RateLimitError

RateLimitError(*args: Any, retry_after: float | None = None, **kwargs: Any)

Bases: APIError

429 — throttled. retry_after (seconds) is parsed from the response; the SDK retries these automatically unless max_retries=0.

UnavailableError

UnavailableError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

503 — a dependency is briefly unavailable (queue dispatch, model loading/ starting, scheduled-off GPU endpoint). Usually retryable; code says which.

ServerError

ServerError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

5xx (other than 503) — unexpected server failure. Retried automatically; report request_id if it persists.

APIConnectionError

APIConnectionError(message: str, *, code: ErrorCode | str = ErrorCode.UNCATEGORIZED, hint: str | None = None, request_id: str | None = None, details: Any = None, status: int | None = None)

Bases: APIError

Transport-level failure (DNS, TLS, timeout) — no HTTP response was received. Retried automatically.

exception_for

exception_for(status: int) -> type[APIError]

Resolve the exception class for an HTTP status (5xx family fallback).

Request params

TypedDicts for every dict-shaped argument.

Request-side TypedDicts — typed keys for every dict-shaped parameter.

These are TypedDicts, NOT pydantic models, on purpose (the OpenAI/Anthropic request-params pattern): a plain dict literal like {"q": "cat"} type-checks against them with zero runtime cost and no construction ceremony, while the SERVER stays the single validator of values. Every shape here mirrors a server pydantic model field-for-field, and the G5 gate (tests/integration/test_gates.py::test_g5_request_typeddicts_mirror_server) fails the build if the server model gains/renames a key this file doesn't have.

Conventions: - Keys are NotRequired wherever the server has a default / accepts omission; Required marks must-send keys inside total=False dicts. - UUIDs and datetimes are typed str — these dicts are passed through to the JSON body verbatim, so callers send str(uuid) / ISO-8601 strings (the explicit keyword params on resource methods accept uuid.UUID objects and stringify for you; pass-through dict INTERIORS do not). - Enum-valued keys accept the enum's string value (e.g. "ready").

AssetFilterParam

Bases: TypedDict

Dataset-scoped asset predicate (assets.bulk_delete / assets.search filters= / project_assets.bulk_add / ProjectScopeParam.filter). Unknown keys 422 (the server forbids extras).

ProjectFilterParam

Bases: TypedDict

Project-scoped asset predicate (workflow + tags + annotation content on top of the asset fields). Used by project_assets.bulk_remove / bulk_delete_annotations, tag bulk ops, and VersionSelectionParam.

Every positive field composes with its negative twin by AND — e.g. tags=["reviewed"], tags_none=["blurry"] = "tagged reviewed AND not blurry". The same value on both sides of a pair is a contradiction (422).

ProjectScopeParam

Bases: TypedDict

projects.create(scope=...) — EXACTLY ONE key.

VersionSelectionParam

Bases: TypedDict

versions.create(selection=...) — EXACTLY ONE key; intersected with the project's in-scope, non-deleted assets.

PolygonPartParam

Bases: TypedDict

One part of a (possibly multi-part) polygon.

AnnotationCreateParam

Bases: TypedDict

One row of annotations.asset_batch_create (asset-scoped). id is the client-minted PK (ADR-0092) — omit to let the server mint; supplying an existing id upserts.

MappedAnnotationCreateParam

Bases: TypedDict

One row of annotations.project_batch_create / bulk_create / import_ndjson. References its asset by asset_id OR filename (asset_id wins if both). No parent_id on the flat mapped path.

AnnotationBatchEditCreateParam

Bases: TypedDict

One create in annotations.batch_edit — the editor path, so id (the client-minted PK) is REQUIRED and must be unique within the batch.

AnnotationBatchEditUpdateParam

Bases: TypedDict

One partial update in annotations.batch_edit — only supplied fields change; type is immutable (delete + create to change kind).

ClassificationConfigParam

Bases: TypedDict

Per-class question config (ADR-0031). options is required for radio/checkbox, ignored for text.

KeypointTopologyParam

Bases: TypedDict

Skeleton definition for a keypoint class (ADR-0030).

AttributeSpecParam

Bases: TypedDict

A per-object question owned by an object class.

ClassSpecParam

Bases: TypedDict

One object class in projects.create(classes=[...]) or classes.create(...)'s keyword form.

ImageClassificationSpecParam

Bases: TypedDict

One image-level question in projects.create(image_classifications=[...]).

TagConfigParam

Bases: TypedDict

Project tag vocabulary (ADR-0050). free_form=True (default) treats allowed_tags as a cosmetic palette; False rejects unknown tags.

SearchQueryPartParam

Bases: TypedDict

One slice of a multimodal search query — set exactly the payload key matching type (text / image_uri / asset_id).

UploadItemParam

Bases: TypedDict

One file in assets.upload_init_batch. client_ref is an opaque token echoed back so you can map results to sources (the SDK's own upload_paths uses the local path).

SegmentPointParam

Bases: TypedDict

One SAM click in ORIGINAL image pixels. label is SAM polarity (1 = foreground, 0 = background), not an ontology class. A single segment(...) call accepts at most 64 of these (a longer list is a 422).

ImageRefParam

Bases: TypedDict

Predict image source — EXACTLY ONE key. For a platform asset, pass its presigned assets.download_url(...) as image_url.

BoxPromptParam

Bases: TypedDict

Few-shot visual prompt: 'find things like the object in this box'.

SourceRefParam

Bases: TypedDict

One overlay source for visualization.annotations.

SplitConfigParam

Bases: TypedDict

Train/val/test split for training.create_run. Ratios must sum to 1; *_tag keys drive the manual (tags-as-split) strategy or opt into materializing an auto split as palette tags (name all three or none).