Convilyn docs

Exceptions

Every error the SDK raises is a subclass of ConvilynError. Catch the base class for a single safety net, or catch a specific subclass when you want to branch on the failure mode.

Hierarchy

ConvilynError                       base — everything the SDK raises
├── AuthError                       no API key configured / malformed key
├── APIError                        HTTP 4xx / 5xx from the Convilyn API
│   ├── RateLimitError              HTTP 429
│   ├── S3UploadError               presigned upload step returned non-success
│   └── RetryExhaustedError         retry policy ran out of attempts
├── JobFailedError                  turbo-lane job reached status `failed`
├── JobTimeoutError                 turbo-lane polling exceeded its timeout
├── GoalJobFailedError              goal-lane workflow reached status `failed`
├── GoalJobTimeoutError             goal-lane polling exceeded its timeout
└── WebSocketError                  goal-lane event stream could not proceed

ConvilynError

class ConvilynError(Exception): ...

Base class for everything the SDK raises. Catching ConvilynError is the recommended way to gate SDK calls behind a single error handler.

from convilyn import ConvilynError

try:
    client.convert.create_and_wait(file=file, target_format="pdf")
except ConvilynError as e:
    log.error("conversion failed", exc_info=e)

The SDK never raises a bare Exception — anything originating in the SDK is one of the classes below.

AuthError

Authentication or authorization failed before any HTTP call. Examples: no API key configured, malformed key prefix (cvl_... expected).

APIError

The Convilyn API returned a non-success HTTP response. Surfaces the envelope {code, message, details} as attributes.

class APIError(ConvilynError):
    status_code: int
    code: str
    message: str
    details: dict[str, Any]

RateLimitError

HTTP 429 — the SDK or caller exceeded the rate limit. Subclass of APIError. Catching APIError covers this case too.

S3UploadError

The presigned upload step of a file upload returned a non-success status. Subclasses APIError so callers catching APIError see it, while still being distinguishable for callers who want to retry uploads with their own policy.

RetryExhaustedError

The retry policy ran out of attempts before the request succeeded. Wraps the final APIError so callers see the last server-side status / code.

class RetryExhaustedError(APIError):
    attempt_count: int   # total attempts including this one

JobFailedError

A turbo-lane job (client.convert.wait, create_and_wait, …) finished with status failed. Attributes mirror the wire-side error envelope so you can correlate against backend logs.

class JobFailedError(ConvilynError):
    job_id: str
    processor_type: str
    code: str
    message: str

JobTimeoutError

A polling helper exceeded its timeout before the job reached a terminal status. The job is still alive on the backend — call client.convert.retrieve(job_id) to fetch its current state.

class JobTimeoutError(ConvilynError):
    job_id: str
    elapsed: float
    timeout: float

GoalJobFailedError

Goal-lane (multi-step) job finished with status failed. Separate class from JobFailedError so you can distinguish turbo-lane conversion failures from goal-lane workflow failures in a try / except chain.

class GoalJobFailedError(ConvilynError):
    job_spec_id: str
    code: str
    message: str

GoalJobTimeoutError

A goal-lane polling helper exceeded its timeout. Like JobTimeoutError but specific to goal-lane workflows.

WebSocketError

Raised when the goal-lane event stream cannot proceed. Covers four conditions:

  • The SDK has no WebSocket URL configured (no ws_url ctor arg, no CONVILYN_WS_URL env var)
  • The transport's connect step raises (DNS, TLS, upgrade rejection)
  • A mid-stream message cannot be parsed into a GoalEvent
  • The connection drops mid-stream

The original payload — when available — is attached on payload so callers can log it.

class WebSocketError(ConvilynError):
    payload: str | None

Catching patterns

Catch everything from the SDK:

try:
    ...
except ConvilynError as e:
    ...

Branch on transient vs permanent:

try:
    ...
except RateLimitError:
    # back off and retry later
except (RetryExhaustedError, JobTimeoutError):
    # transient — caller should retry the workflow
except ConvilynError:
    # something else SDK-originated

Distinguish lanes:

try:
    ...
except JobFailedError as e:
    log.error(f"turbo-lane job {e.job_id} failed: {e.code}")
except GoalJobFailedError as e:
    log.error(f"goal-lane workflow {e.job_spec_id} failed: {e.code}")