Skip to main content
The SDK raises typed exceptions for API errors. All errors extend ApiError and include the HTTP status code, response headers, and body.

Error types

ExceptionStatus CodeWhen it’s raised
BadRequestError400Invalid request parameters.
ForbiddenError403Invalid or missing API key.
NotFoundError404Resource (run, workflow, session) not found.
ConflictError409Resource conflict (e.g., duplicate creation).
UnprocessableEntityError422Request validation failed.
ApiErrorAnyBase class for all API errors. Catch this as a fallback.
The specific error classes live in skyvern.client.errors. The base ApiError class lives in skyvern.client.core:
from skyvern.client.core import ApiError
from skyvern.client.errors import (
    BadRequestError,
    ForbiddenError,
    NotFoundError,
    ConflictError,
    UnprocessableEntityError,
)

Catching errors

from skyvern import Skyvern
from skyvern.client.core import ApiError
from skyvern.client.errors import NotFoundError

client = Skyvern(api_key="YOUR_API_KEY")

try:
    run = await client.get_run("tsk_nonexistent")
except NotFoundError as e:
    print(f"Run not found: {e.body}")
except ApiError as e:
    print(f"API error {e.status_code}: {e.body}")

Error properties

Every error has these attributes:
PropertyTypeDescription
status_codeint | NoneHTTP status code.
bodyAnyResponse body (usually a dict with error details).
headersdict[str, str] | NoneResponse headers.

Timeouts

Two different timeouts apply:

HTTP request timeout

Controls how long the SDK waits for the HTTP response from the Skyvern API. Set it in the constructor or per-request:
# Global timeout (applies to all requests)
client = Skyvern(api_key="YOUR_API_KEY", timeout=30.0)

# Per-request timeout
from skyvern.client.core import RequestOptions

result = await client.get_run(
    "tsk_abc123",
    request_options=RequestOptions(timeout_in_seconds=10),
)

Completion timeout

Controls how long wait_for_completion polls before giving up. This is separate from the HTTP timeout:
try:
    result = await client.run_task(
        prompt="Extract data",
        url="https://example.com",
        wait_for_completion=True,
        timeout=300,  # Give up after 5 minutes
    )
except TimeoutError:
    print("Task didn't complete in time")
The completion timeout raises Python’s built-in TimeoutError (via asyncio.timeout), not ApiError.

Retries

Configure automatic retries for transient failures using RequestOptions:
from skyvern.client.core import RequestOptions

result = await client.run_task(
    prompt="Extract product data",
    url="https://example.com/products",
    request_options=RequestOptions(max_retries=3),
)
Retries apply to the HTTP request level (network errors, 5xx responses). They do not retry the entire task if it fails at the AI level — use get_run to check the status and re-run if needed.

Run failure vs API errors

There are two distinct failure modes: API error — The HTTP request itself failed. The SDK raises an exception.
from skyvern.client.core import ApiError

try:
    result = await client.run_task(prompt="...")
except ApiError as e:
    print(f"API call failed: {e.status_code}")
Run failure — The API call succeeded, but the task/workflow failed during execution. No exception is raised. Check the status field:
result = await client.run_task(
    prompt="Fill out the form",
    url="https://example.com",
    wait_for_completion=True,
)

if result.status == "failed":
    print(f"Task failed: {result.failure_reason}")
elif result.status == "timed_out":
    print(f"Task exceeded step limit after {result.step_count} steps")
elif result.status == "completed":
    print(f"Success: {result.output}")

Run statuses

StatusDescription
createdRun initialized, not yet queued.
queuedWaiting for an available browser.
runningAI is executing.
completedFinished successfully.
failedEncountered an error during execution.
terminatedManually stopped.
timed_outExceeded step limit (max_steps).
canceledCanceled before starting.