Skip to main content
The SDK applies different timeout strategies to one-shot (unary) calls and to streams, and it retries only when doing so is safe. This page is the single source of truth for that behavior.

Defaults

Unary requests

A unary call (complete, images, code, documents, job, list endpoints, …) is bounded by timeoutMs end-to-end. If it elapses, the SDK aborts the request and throws a TheoTimeoutError (error.kind === "timeout", error.timeoutMs carries the budget).

Streaming requests

stream() is not capped by a total-duration timeout — a long but healthy stream can run for minutes. Instead:
  • timeoutMs guards the connection / first byte. If headers never arrive, you get a TheoTimeoutError (“Stream did not start…”).
  • streamIdleTimeoutMs guards the gap between chunks. The timer resets on every chunk; if the stream goes silent for longer than the window, the SDK aborts it and the async iterator throws a TheoTimeoutError.
TheoStream.cancel() is different from a timeout. Cancelling ends the iterator cleanly (no throw); a timeout throws TheoTimeoutError.

Retry policy

The SDK retries automatically on:
  • 429 — rate limited (honors Retry-After up to 60s)
  • 5xx — server errors (exponential backoff: 1s, 2s, 4s, capped at 8s) It does not retry 4xx (other than 429).

Timeouts are not retried on writes

A timed-out POST (complete, research, video, …) is never retried. Re-issuing a non-idempotent generation could run — and bill — the same work twice. The timeout is terminal for those methods; only idempotent reads (GET/HEAD) retry on timeout.
If you need at-most-once semantics across your own retries, send an Idempotency-Key header (supported platform-wide) so a replay reuses the original result instead of generating again.

Per-mode guidance

  • fast / auto: the 30s default is plenty.
  • think / code: can run longer — raise timeoutMs (e.g. 60–120s) for big prompts.
  • research / video: do not send these to complete() / stream(). They are asynchronous and run as jobs — use theo.research() / theo.video() + theo.waitForJob(). The SDK throws a TheoUsageError immediately if you try. See Async Jobs.

Errors

All of the above surface through the SDK error hierarchy. See Error Handling for TheoTimeoutError, TheoCancelledError, TheoUsageError, and the kind discriminator.