Dream Engines

Errors & retries

Every SDK-raised error inherits from dream.DreamError, so a single except dream.DreamError: catches everything — but the typed subclasses let you handle specific conditions cleanly.

Taxonomy

ClassTriggerstatus_codeRetryable?
dream.AuthError401, 403401/403no
dream.InsufficientCreditsError402402no
dream.RateLimitError429429yes (honors Retry-After)
dream.ModelNotFoundError404 on /v1/models/{slug}404no
dream.ValidationError4xx other (server-side)4xxno
dream.ServerError5xx, transport error5xx or None502/503/504/transport: yes
dream.EngineError200 OK but engine signaled failure200no (rare)
dream.ModelNotActiveErrorclient-side: wrong handle.predictn/ano
dream.InputValidationErrorclient-side: bad shape/dtype/pathn/ano

InputValidationError and ModelNotActiveError are also ValueError / RuntimeError so older except ValueError: patterns still catch them.

Common attributes

PYTHON
class DreamError(Exception):
message: str
status_code: int | None # HTTP status, None for client-side
request_id: str | None # echo from X-DreamEngine-Request-Id
body: str | None # raw response body if available

RateLimitError adds retry_after: float | None.

InsufficientCreditsError adds the customer's current balance and the predicted cost the engine wanted to debit:

PYTHON
class InsufficientCreditsError(DreamError):
balance_cents: int # current balance, integer cents
requested_cents: int # cost of this predict, integer cents
@property
def balance_usd(self) -> float: ... # balance_cents / 100
@property
def requested_usd(self) -> float: ... # requested_cents / 100

The 402 fires before GPU work — you only see this error when the predict didn't actually run. To recover:

PYTHON
try:
rollout = model.predict(start_frame=img, actions=acts)
except dream.InsufficientCreditsError as e:
session = client.billing.topup(amount_usd=25.00)
print("Top up here:", session.url)

See Billing for the credits + top-up surface.

Idiomatic handling

PYTHON
import time, dream
try:
rollout = client.models.get("dreamdojo-2b-gr1").predict(...)
except dream.AuthError:
# Re-authenticate / surface to user
raise
except dream.RateLimitError as e:
# SDK already retried 3x; backoff further or escalate
time.sleep(e.retry_after or 5.0)
except dream.ValidationError as e:
# Server rejected the request shape; you sent something invalid
log.error("server validation: %s", e)
except dream.DreamError as e:
# Catch-all (Auth, RateLimit, ModelNotFound, ServerError, etc.)
log.exception("dream-engine error %s: %s", e.status_code, e)

Retries

The SDK retries automatically on:

  • 429 Too Many Requests (honors Retry-After)
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Timeout
  • httpx.TransportError (DNS, TLS, conn-refused, etc.)

Defaults — overridable via RetryPolicy(...) on the Client:

PYTHON
dream.RetryPolicy(
max_attempts=3, # 1 disables retries
base_delay_s=0.25, # → 0.25, 0.5, 1.0, 2.0, 4.0 (capped)
max_delay_s=4.0,
jitter=True, # ±50%
)

Errors not in the retryable set (auth, validation, 500, model not-found) raise immediately — no retry, no backoff.

What's never raised

  • httpx.HTTPStatusError, httpx.RequestError, etc. — the SDK wraps every httpx exception in a DreamError subclass at the transport boundary. If you ever see a raw httpx exception escape, that's a bug; please file it.
  • requests.* — the SDK uses httpx, not requests.

Server-side error bodies

When the server returns a 4xx/5xx with a JSON body shaped like {"detail": "..."} (FastAPI default), the SDK extracts that string into the error's message. If parsing fails, the raw body lands in error.body.

Future versions may switch to RFC 7807 application/problem+json bodies; the SDK already prefers problem+json when present and falls back gracefully.

Testing your error handling

For unit tests, construct errors directly without making a network call:

PYTHON
import dream
err = dream.RateLimitError("rate limited", retry_after=5.0, status_code=429)
assert err.retry_after == 5.0
assert isinstance(err, dream.DreamError)

The errors are plain dataclasses; no httpx response object required.