DaytonaDocs

Errors

The error hierarchy and how to handle failures.

Every failure in the TypeScript SDK is thrown as DaytonaError or one of its subclasses — named to match the official Daytona SDK so existing error handling ports unchanged. HTTP failures map onto subclasses by status code; client-side failures (validation, timeouts, connection errors) use the same classes.

Hierarchy

All classes are importable from @rlp/sdk:

TypeScript
import {
  DaytonaError,
  DaytonaValidationError,
  DaytonaAuthenticationError,
  DaytonaAuthorizationError,
  DaytonaNotFoundError,
  DaytonaConflictError,
  DaytonaRateLimitError,
  DaytonaTimeoutError,
  DaytonaConnectionError,
  DaytonaNotSupportedError,
} from '@rlp/sdk'
ErrorHTTP statusThrown when
DaytonaErrorany / noneBase class; also thrown directly for unmapped statuses and generic failures (e.g. a sandbox landing in error).
DaytonaValidationError400Invalid input — server-side, or client-side (missing apiUrl, negative timeout, missing snapshot/image).
DaytonaAuthenticationError401Authentication failed, including a missing API key at client construction.
DaytonaAuthorizationError403Request forbidden.
DaytonaNotFoundError404Resource not found.
DaytonaConflictError409Resource conflict — e.g. deleting a volume that is still attached.
DaytonaRateLimitError429Rate limit exceeded.
DaytonaNotSupportedError501Operation not supported — e.g. stop()/pause()/fork() on a non-persistent sandbox, or archive().
DaytonaTimeoutErrorAn HTTP request or a wait (e.g. waitUntilStarted) timed out.
DaytonaConnectionErrorThe request never got a response — the network connection failed.

Every instance carries:

PropertyTypeDescription
messagestringHuman-readable message (from the API's error body when available).
statusCodenumber | undefinedHTTP status, when the error came from a response.
errorCodestring | undefinedMachine-readable code from the API body, when present.

Subclasses set name and their prototype correctly, so both instanceof checks and error.name work.

Patterns

Handle a create timeout by inspecting and cleaning up the sandbox:

TypeScript
import { Daytona, DaytonaTimeoutError } from '@rlp/sdk'
 
const daytona = new Daytona()
try {
  const sandbox = await daytona.create({ image: 'node:22-slim' }, { timeout: 30 })
} catch (e) {
  if (e instanceof DaytonaTimeoutError) {
    // The sandbox may still be booting; find it and decide whether to wait or delete.
    for (const sb of await daytona.list()) {
      if (sb.state === 'creating' || sb.state === 'starting') {
        await sb.waitUntilStarted(120)
      }
    }
  } else {
    throw e
  }
}

Retry on rate limits:

TypeScript
import { DaytonaRateLimitError } from '@rlp/sdk'
 
for (let attempt = 0; attempt < 5; attempt++) {
  try {
    await sandbox.process.executeCommand('make test')
    break
  } catch (e) {
    if (!(e instanceof DaytonaRateLimitError)) throw e
    await new Promise((r) => setTimeout(r, 2 ** attempt * 1000))
  }
}

Branch on capability — persistent-only operations throw DaytonaNotSupportedError locally:

TypeScript
import { DaytonaNotSupportedError } from '@rlp/sdk'
 
try {
  await sandbox.stop()
} catch (e) {
  if (e instanceof DaytonaNotSupportedError) {
    // Not a persistent sandbox — there is no warm stop; delete instead.
    await sandbox.delete()
  } else {
    throw e
  }
}

Detect a spot-evicted sandbox: eviction pauses a persistent spot sandbox (or deletes an ephemeral one), so a non-running persistent spot sandbox can simply be started again. See spot sandboxes.

TypeScript
await sandbox.refreshData()
if (sandbox.state === 'stopped') {
  await sandbox.start() // warm-resume after eviction
}

On this page