From f887c9b36e83a5b427d63b10d36cf097dfc4890c Mon Sep 17 00:00:00 2001 From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:54:40 +0000 Subject: [PATCH] docs: document exec per-request timeout and SandboxTimeoutError --- sandbox/sdk/python/errors.mdx | 2 ++ sandbox/sdk/python/reference.mdx | 17 ++++++++++++++++- sandbox/sdk/typescript/errors.mdx | 2 ++ sandbox/sdk/typescript/reference.mdx | 22 +++++++++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/sandbox/sdk/python/errors.mdx b/sandbox/sdk/python/errors.mdx index 0ca41881..041b4b6f 100644 --- a/sandbox/sdk/python/errors.mdx +++ b/sandbox/sdk/python/errors.mdx @@ -11,6 +11,7 @@ from porter_sandbox import ( NotFoundError, RateLimitError, SandboxError, + SandboxTimeoutError, ServerError, ) ``` @@ -24,6 +25,7 @@ from porter_sandbox import ( | `NotFoundError` | A sandbox, volume, or other resource cannot be found. | | `RateLimitError` | The API returns a rate limit response. | | `ServerError` | The API returns a server-side error. | +| `SandboxTimeoutError` | A request exceeds its timeout. Never retried, since the server may still be executing the request. | Each `SandboxError` includes: diff --git a/sandbox/sdk/python/reference.mdx b/sandbox/sdk/python/reference.mdx index 5e522efa..4d306ec3 100644 --- a/sandbox/sdk/python/reference.mdx +++ b/sandbox/sdk/python/reference.mdx @@ -102,10 +102,25 @@ sandbox.terminate() | Method | Description | | ------ | ----------- | | `refresh()` | Refetches status and updates `phase` and `tags`. | -| `exec(command)` | Runs a command in the sandbox and returns stdout, stderr, and exit code. | +| `exec(command, timeout=None)` | Runs a command in the sandbox and returns stdout, stderr, and exit code. | | `logs(since=None, limit=None)` | Fetches structured log lines. | | `terminate()` | Terminates the sandbox. | +### `exec` timeouts + +`exec` is long-running: the client sends no timeout by default, so the call waits for the command to exit. Pass `timeout` (seconds) to cap how long the client waits. When the timeout elapses, the SDK raises `SandboxTimeoutError` and does not retry, since the command may still be running server-side. + +```python +from porter_sandbox import SandboxTimeoutError + +try: + result = sandbox.exec(["sleep", "120"], timeout=30.0) +except SandboxTimeoutError: + print("exec exceeded 30s; the command may still be running in the sandbox") +``` + +The client-wide `timeout` on `Porter` still applies to every other request (30 seconds by default). + ## Volumes Volumes are persistent storage that can be mounted into sandboxes. diff --git a/sandbox/sdk/typescript/errors.mdx b/sandbox/sdk/typescript/errors.mdx index 4565c7e4..e234489e 100644 --- a/sandbox/sdk/typescript/errors.mdx +++ b/sandbox/sdk/typescript/errors.mdx @@ -11,6 +11,7 @@ import { NotFoundError, RateLimitError, SandboxError, + SandboxTimeoutError, ServerError, } from "porter-sandbox"; ``` @@ -24,6 +25,7 @@ import { | `NotFoundError` | A sandbox, volume, or other resource cannot be found. | | `RateLimitError` | The API returns a rate limit response. | | `ServerError` | The API returns a server-side error. | +| `SandboxTimeoutError` | A request exceeds its timeout. Never retried, since the server may still be executing the request. | Each `SandboxError` includes: diff --git a/sandbox/sdk/typescript/reference.mdx b/sandbox/sdk/typescript/reference.mdx index e51fecb2..35906c76 100644 --- a/sandbox/sdk/typescript/reference.mdx +++ b/sandbox/sdk/typescript/reference.mdx @@ -109,10 +109,30 @@ await sandbox.terminate(); | Method | Description | | ------ | ----------- | | `refresh()` | Refetches status and updates `phase` and `tags`. | -| `exec(command)` | Runs a command in the sandbox and returns stdout, stderr, and exit code. | +| `exec(command, requestOptions?)` | Runs a command in the sandbox and returns stdout, stderr, and exit code. | | `logs(options?)` | Fetches structured log lines. | | `terminate()` | Terminates the sandbox. | +### `exec` timeouts + +`exec` is long-running: the client sends no timeout by default, so the call waits for the command to exit. Pass `requestOptions.timeoutMs` to cap how long the client waits. When the timeout elapses, the SDK throws `SandboxTimeoutError` and does not retry, since the command may still be running server-side. + +```typescript +import { SandboxTimeoutError } from "porter-sandbox"; + +try { + const result = await sandbox.exec(["sleep", "120"], { timeoutMs: 30_000 }); +} catch (error) { + if (error instanceof SandboxTimeoutError) { + console.error("exec exceeded 30s; the command may still be running in the sandbox"); + } else { + throw error; + } +} +``` + +The client-wide `timeoutMs` on `Porter` still applies to every other request (30 seconds by default). + ## Volumes Volumes are persistent storage that can be mounted into sandboxes.