from declaw import (
SandboxException,
TimeoutException,
NotFoundException,
AuthenticationException,
InvalidArgumentException,
NotEnoughSpaceException,
TemplateException,
BuildException,
FileUploadException,
GitAuthException,
GitUpstreamException,
CommandExitException,
InsufficientBalanceException,
RateLimitException,
)
All SDK exceptions inherit from SandboxException, which inherits from the built-in Exception. You can catch the base class to handle any Declaw error, or catch specific subclasses for granular handling.
Exception hierarchy
Exception
└── SandboxException
├── TimeoutException
├── NotFoundException
├── AuthenticationException
├── InvalidArgumentException
├── NotEnoughSpaceException
├── FileUploadException
├── GitAuthException
├── GitUpstreamException
├── CommandExitException
├── InsufficientBalanceException
├── RateLimitException
└── TemplateException
└── BuildException
SandboxException
Base class for all Declaw exceptions.
class SandboxException(Exception):
def __init__(self, message: str = "", *, sandbox_id: str | None = None):
self.sandbox_id = sandbox_id
...
Attributes
| Attribute | Type | Description |
|---|
sandbox_id | str | None | The sandbox ID involved in the error, when available. |
TimeoutException
Raised when an operation exceeds its configured timeout.
from declaw import Sandbox, TimeoutException
try:
result = sbx.commands.run("sleep 300", timeout=10)
except TimeoutException as e:
print(f"Command timed out in sandbox {e.sandbox_id}")
Inherits sandbox_id from SandboxException.
NotFoundException
Raised when the sandbox or a requested resource does not exist (HTTP 404).
from declaw import Sandbox, NotFoundException
try:
sbx = Sandbox.connect("nonexistent-id", api_key="key", domain="host:8080")
except NotFoundException as e:
print("Sandbox not found:", e)
AuthenticationException
Raised when the API key is missing or invalid (HTTP 401/403).
from declaw import Sandbox, AuthenticationException
try:
sbx = Sandbox.create(api_key="wrong-key", domain="host:8080")
except AuthenticationException:
print("Invalid API key")
InvalidArgumentException
Raised when a method receives an argument that fails validation.
from declaw import NetworkPolicy, InvalidArgumentException
try:
NetworkPolicy(allow_out=["not-a-valid-entry!!"])
except InvalidArgumentException as e:
print("Bad argument:", e)
NotEnoughSpaceException
Raised when the sandbox filesystem is full and a write operation fails.
from declaw import NotEnoughSpaceException
try:
sbx.files.write("/data/large_file.bin", large_bytes)
except NotEnoughSpaceException:
print("Sandbox disk is full")
CommandExitException
Raised when a command exits with a non-zero exit code. Contains the full stdout, stderr, and exit code.
class CommandExitException(SandboxException):
def __init__(
self,
message: str = "",
*,
exit_code: int = 1,
stdout: str = "",
stderr: str = "",
sandbox_id: str | None = None,
):
self.exit_code = exit_code
self.stdout = stdout
self.stderr = stderr
Attributes
| Attribute | Type | Description |
|---|
exit_code | int | The process exit code. |
stdout | str | Accumulated stdout output. |
stderr | str | Accumulated stderr output. |
from declaw import CommandExitException
try:
result = sbx.commands.run("python3 -c \"raise ValueError('oops')\"")
except CommandExitException as e:
print(f"Exit code: {e.exit_code}")
print(f"Stderr: {e.stderr}")
CommandExitException is only raised by CommandHandle.wait(). The main
sbx.commands.run() method returns a CommandResult with a non-zero
exit_code rather than raising — you must check result.exit_code yourself
unless you use a background handle.
TemplateException
Base class for template-related errors.
BuildException
Raised when a Template.build() call fails.
from declaw import BuildException
try:
info = Template.build(template, "my-alias", api_key="key", domain="host:8080")
except BuildException as e:
print("Build failed:", e)
FileUploadException
Raised when uploading a file to the sandbox fails (e.g. network error during multipart upload).
GitAuthException
Raised when git operations inside the sandbox fail due to authentication errors.
GitUpstreamException
Raised when git operations fail due to upstream repository errors.
InsufficientBalanceException
Raised when the account has insufficient balance to start or continue a
sandbox operation (HTTP 402).
from declaw import Sandbox, InsufficientBalanceException
try:
sbx = Sandbox.create(api_key="key", domain="host:8080")
except InsufficientBalanceException as e:
print(f"Top up required for wallet: {e.wallet_type}")
Attributes
| Attribute | Type | Description |
|---|
wallet_type | str | Which wallet is out of balance (e.g. "sandbox", "guardrails"). |
RateLimitException
Raised when the account exceeds its rate limit (HTTP 429). Inspect
retry_after and back off before retrying.
import time
from declaw import Sandbox, RateLimitException
try:
sbx = Sandbox.create(api_key="key", domain="host:8080")
except RateLimitException as e:
if e.retry_after:
time.sleep(e.retry_after)
Attributes
| Attribute | Type | Description |
|---|
retry_after | float | None | Seconds to wait before retrying, when provided by the server. |
limit | int | None | Configured request limit for the window. |
remaining | int | None | Requests remaining in the current window. |
Catching all Declaw errors
from declaw import SandboxException
try:
sbx = Sandbox.create(api_key="key", domain="host:8080")
result = sbx.commands.run("my-command")
except SandboxException as e:
print(f"Declaw error: {e}")
if e.sandbox_id:
print(f"Sandbox ID: {e.sandbox_id}")
finally:
sbx.kill()
Retry patterns
Simple retry with backoff
import time
from declaw import Sandbox, TimeoutException, SandboxException
def run_with_retry(cmd: str, retries: int = 3, delay: float = 1.0) -> str:
sbx = Sandbox.create(api_key="key", domain="host:8080")
try:
for attempt in range(retries):
try:
result = sbx.commands.run(cmd, timeout=30)
return result.stdout
except TimeoutException:
if attempt < retries - 1:
time.sleep(delay * (2 ** attempt))
else:
raise
finally:
sbx.kill()
Retry with tenacity
from tenacity import retry, stop_after_attempt, wait_exponential
from declaw import Sandbox, TimeoutException
@retry(
reraise=True,
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10),
retry=lambda e: isinstance(e, TimeoutException),
)
def run_command(sbx: Sandbox, cmd: str) -> str:
result = sbx.commands.run(cmd, timeout=30)
return result.stdout
Handle non-zero exit codes
from declaw import Sandbox
sbx = Sandbox.create(api_key="key", domain="host:8080")
try:
result = sbx.commands.run("python3 risky_script.py")
if result.exit_code != 0:
print(f"Script failed (exit {result.exit_code})")
print(f"Stderr: {result.stderr}")
else:
print(result.stdout)
finally:
sbx.kill()
Async error handling
import asyncio
from declaw import AsyncSandbox, TimeoutException
async def main():
sbx = await AsyncSandbox.create(api_key="key", domain="host:8080")
try:
result = await sbx.run_command("long-running-task", timeout=60)
print(result.stdout)
except TimeoutException:
print("Timed out — killing sandbox")
finally:
await sbx.kill()
asyncio.run(main())