Error Handling
The SDK provides typed exceptions for different error conditions.
Error Types
| Error | Description |
|---|---|
SmolvmError | Base class for all SDK errors |
ConnectionError | Cannot connect to server |
TimeoutError | Request timed out |
NotFoundError | Resource not found (404) |
ConflictError | Resource conflict (409) |
BadRequestError | Invalid request (400) |
InternalError | Server error (500) |
ExecutionError | Command failed (non-zero exit) |
Basic Error Handling
typescript
import {
SmolvmError,
NotFoundError,
ConflictError,
TimeoutError,
ConnectionError,
ExecutionError,
} from 'smolvm';
try {
const machine = await Machine.create({ name: 'test' });
const result = await machine.exec(['some-command']);
result.assertSuccess();
} catch (error) {
if (error instanceof ConnectionError) {
console.log('Cannot connect to smolvm server');
console.log('Is the server running? Try: smolvm serve');
} else if (error instanceof NotFoundError) {
console.log('Machine not found');
} else if (error instanceof ConflictError) {
console.log('Machine already exists');
} else if (error instanceof TimeoutError) {
console.log('Request timed out');
} else if (error instanceof ExecutionError) {
console.log(`Command failed with exit code: ${error.exitCode}`);
console.log(`stderr: ${error.stderr}`);
} else if (error instanceof SmolvmError) {
console.log(`SDK error: ${error.message}`);
} else {
throw error;
}
}python
from smolvm import (
SmolvmError,
NotFoundError,
ConflictError,
TimeoutError,
ConnectionError,
ExecutionError,
)
try:
machine = await Machine.create(MachineConfig(name="test"))
result = await machine.exec(["some-command"])
result.assert_success()
except ConnectionError:
print("Cannot connect to smolvm server")
print("Is the server running? Try: smolvm serve")
except NotFoundError:
print("Machine not found")
except ConflictError:
print("Machine already exists")
except TimeoutError:
print("Request timed out")
except ExecutionError as e:
print(f"Command failed with exit code: {e.exit_code}")
print(f"stderr: {e.stderr}")
except SmolvmError as e:
print(f"SDK error: {e}")ExecutionError
Raised when a command exits with a non-zero status.
typescript
interface ExecutionError extends SmolvmError {
exitCode: number;
stdout: string;
stderr: string;
}
try {
const result = await machine.exec(['false']); // exits with 1
result.assertSuccess(); // throws ExecutionError
} catch (error) {
if (error instanceof ExecutionError) {
console.log(`Exit code: ${error.exitCode}`);
console.log(`Output: ${error.stdout}`);
console.log(`Error: ${error.stderr}`);
}
}python
@dataclass
class ExecutionError(SmolvmError):
exit_code: int
stdout: str
stderr: str
try:
result = await machine.exec(["false"]) # exits with 1
result.assert_success() # raises ExecutionError
except ExecutionError as e:
print(f"Exit code: {e.exit_code}")
print(f"Output: {e.stdout}")
print(f"Error: {e.stderr}")Handling Without Exceptions
Check results without throwing:
typescript
const result = await machine.exec(['maybe-fails']);
if (!result.success) {
console.log(`Command failed with code ${result.exitCode}`);
console.log(`stderr: ${result.stderr}`);
} else {
console.log(`Success: ${result.stdout}`);
}python
result = await machine.exec(["maybe-fails"])
if not result.success:
print(f"Command failed with code {result.exit_code}")
print(f"stderr: {result.stderr}")
else:
print(f"Success: {result.stdout}")Retry Logic
Implement retry for transient failures:
typescript
import { TimeoutError, ConnectionError } from 'smolvm';
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
delay = 1000
): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error instanceof TimeoutError || error instanceof ConnectionError) {
if (i === maxRetries - 1) throw error;
await new Promise(r => setTimeout(r, delay * (i + 1)));
} else {
throw error;
}
}
}
throw new Error('Unreachable');
}
const result = await withRetry(() => machine.exec(['slow-command']));python
import asyncio
from smolvm import TimeoutError, ConnectionError
async def with_retry(fn, max_retries=3, delay=1.0):
for i in range(max_retries):
try:
return await fn()
except (TimeoutError, ConnectionError):
if i == max_retries - 1:
raise
await asyncio.sleep(delay * (i + 1))
result = await with_retry(lambda: machine.exec(["slow-command"]))Cleanup on Error
Always clean up resources, even on error:
typescript
// Using try/finally
const machine = await Machine.create({ name: 'cleanup-example' });
try {
await machine.exec(['risky-command']);
} finally {
await machine.stop();
await machine.delete();
}
// Or use withMachine helper
import { withMachine } from 'smolvm';
await withMachine({ name: 'auto-cleanup' }, async (machine) => {
await machine.exec(['risky-command']);
});
// Automatically cleaned uppython
# Using context manager (recommended)
async with Machine(config) as machine:
await machine.start()
await machine.exec(["risky-command"])
# Automatically cleaned up, even on error
# Or manually with try/finally
machine = await Machine.create(config)
try:
await machine.exec(["risky-command"])
finally:
await machine.stop()
await machine.delete()
await machine.close()