Skip to main content
    Ivy Biosciences Docs/Call the platform/API/SDKs/SDK errors

    SDK errors

    IvyError hierarchy — IvyApiError, IvyWebSocketError, IvyTimeoutError with handling patterns

    This page documents the error classes the SDK throws so you can catch and respond to failures precisely — distinguishing an expired auth token from a rate limit, a missing job, a dropped WebSocket, or a timed-out wait. Reach for it when you're writing try/catch logic or an onError handler and need to know which error type carries which recovery hint (for example, IvyApiError.isRateLimited or isNotFound). Every SDK error extends IvyError, so a single catch block can handle them all; the errors are raised by the Client, Jobs, and WebSocket calls documented alongside.

    SDK Errors Reference

    Planned specification. @ivybiosciences/sdk is not released, and there is no package to install. This page describes the SDK's planned interface. To call the platform today, use the REST API, the ivybloom CLI, or the MCP server.

    All SDK errors extend IvyError, making it easy to catch any IvyAI-specific error in a single catch block while still distinguishing between API, WebSocket, and timeout errors.

    import {
      IvyError,
      IvyApiError,
      IvyWebSocketError,
      IvyTimeoutError,
    } from "@ivybiosciences/sdk"

    Error Hierarchy

    Error (built-in)
    └── IvyError
        ├── IvyApiError         (HTTP non-2xx responses)
        ├── IvyWebSocketError   (WebSocket connection failures)
        └── IvyTimeoutError     (Operation timeouts)

    IvyError

    Base error class for all IvyAI SDK errors.

    class IvyError extends Error {
      readonly code?: string
      constructor(message: string, code?: string)
    }
    PropertyTypeDescription
    messagestringHuman-readable error description
    codestring?Machine-readable error code (e.g., "AUTH_REQUIRED")
    namestringAlways "IvyError"

    Examples

    try {
      await ivy.jobs.submit(params)
    } catch (e) {
      if (e instanceof IvyError) {
        // Any SDK error
        console.log(e.message, e.code)
      }
    }

    IvyApiError

    Error thrown when the IvyAI API returns a non-2xx response. Provides structured access to the HTTP status code and convenience getters for common error categories.

    class IvyApiError extends IvyError {
      readonly status: number
      readonly detail: string
      readonly body: unknown
    
      get isRateLimited(): boolean    // status === 429
      get isNotFound(): boolean       // status === 404
      get isUnauthorized(): boolean   // status === 401
      get isForbidden(): boolean      // status === 403
      get isServerError(): boolean    // status >= 500
    }

    Constructor

    new IvyApiError(response: {
      status?: number    // Defaults to 500
      detail?: string    // Defaults to "API error: {status}"
      body?: unknown     // Raw response body for debugging
    })

    Properties

    PropertyTypeDescription
    statusnumberHTTP status code (400, 401, 404, 422, 429, 500, etc.)
    detailstringError message from the API response body
    bodyunknownRaw response body for debugging

    Convenience Getters

    GetterReturns true whenRecommended action
    isRateLimitedHTTP 429Back off and retry
    isNotFoundHTTP 404Check resource ID
    isUnauthorizedHTTP 401Re-authenticate
    isForbiddenHTTP 403Check permissions
    isServerErrorHTTP 5xxRetry (usually transient)

    Examples

    try {
      await ivy.jobs.submit({ toolName: "esmfold", parameters: {} })
    } catch (e) {
      if (e instanceof IvyApiError) {
        console.log(e.status)        // 422
        console.log(e.detail)        // "Invalid protein sequence"
        console.log(e.isNotFound)    // false
        console.log(e.isRateLimited) // false
      }
    }
    
    // Rate limit handling
    try {
      await ivy.jobs.submit(params)
    } catch (e) {
      if (e instanceof IvyApiError && e.isRateLimited) {
        await new Promise(r => setTimeout(r, 60_000)) // Wait 1 minute
        await ivy.jobs.submit(params) // Retry
      }
    }
    
    // Not found handling
    try {
      const status = await ivy.jobs.getStatus("job_nonexistent")
    } catch (e) {
      if (e instanceof IvyApiError && e.isNotFound) {
        console.log("Job does not exist or has expired")
      }
    }

    IvyWebSocketError

    Error thrown when a WebSocket connection fails or closes unexpectedly.

    class IvyWebSocketError extends IvyError {
      readonly closeCode: number
      constructor(closeCode: number, reason: string)
    }

    Properties

    PropertyTypeDescription
    closeCodenumberThe WebSocket close code
    messagestring"WebSocket closed: {reason} (code: {code})"

    Common Close Codes

    CodeMeaningSDK Behavior
    1000Normal closureNo reconnect
    1001Server going away (deploy)Auto-reconnect
    1006Abnormal closure (network)Auto-reconnect
    1008Policy violation (bad token)Auto-reconnect (new token)
    4001Too many connections per userNo reconnect (close other connections)
    4002Too many connections per jobNo reconnect (close other connections)
    4003Authentication failedNo reconnect (re-authenticate)
    4004Guest feature disabledNo reconnect

    Examples

    import { IvyWebSocketError } from "@ivybiosciences/sdk"
    
    try {
      await ivy.websocket.connect("job_abc123")
    } catch (e) {
      if (e instanceof IvyWebSocketError) {
        console.log(`Close code: ${e.closeCode}`)
        if (e.closeCode === 4003) {
          // Authentication issue — token may have expired
        }
      }
    }

    IvyTimeoutError

    Error thrown when an operation exceeds its configured timeout. Most commonly occurs during submitAndWait().

    class IvyTimeoutError extends IvyError {
      readonly timeoutMs: number
      constructor(timeoutMs: number)
    }

    Properties

    PropertyTypeDescription
    timeoutMsnumberThe timeout value that was exceeded, in milliseconds
    messagestring"Operation timed out after {timeoutMs}ms"

    Examples

    import { IvyTimeoutError } from "@ivybiosciences/sdk"
    
    try {
      await ivy.jobs.submitAndWait(params, { timeout: 30_000 }) // 30s
    } catch (e) {
      if (e instanceof IvyTimeoutError) {
        console.log(`Timed out after ${e.timeoutMs}ms`)
        // The job is still running server-side — check status manually
      }
    }

    Error Handling Patterns

    Catch-All SDK Errors

    try {
      const result = await ivy.jobs.submitAndWait(params)
    } catch (e) {
      if (e instanceof IvyError) {
        // Any SDK error — log and display
        console.error(`[${e.name}] ${e.message}`)
      } else {
        // Non-SDK error (network, runtime, etc.)
        throw e
      }
    }

    Comprehensive Error Handling

    try {
      const result = await ivy.jobs.submitAndWait(params, { timeout: 120_000 })
      // Handle success...
    } catch (e) {
      if (e instanceof IvyApiError) {
        if (e.isRateLimited) {
          showToast("Rate limited — please wait and try again")
        } else if (e.isUnauthorized) {
          redirectToLogin()
        } else if (e.isNotFound) {
          showToast("Resource not found")
        } else if (e.isServerError) {
          showToast("Server error — retrying automatically")
        } else {
          showToast(`Error: ${e.detail}`)
        }
      } else if (e instanceof IvyTimeoutError) {
        showToast(`Job timed out after ${e.timeoutMs / 1000}s`)
      } else if (e instanceof IvyWebSocketError) {
        showToast("Connection lost — using polling fallback")
      }
    }

    Harness Error Codes

    The Harness Sessions API returns structured error codes with machine-readable identifiers and recovery hints. These are separate from HTTP status codes.

    interface HarnessError {
      error: string        // Human-readable message
      code: string         // Machine-readable code (e.g., "SESSION_NOT_FOUND")
      recoveryHint?: string // Suggested fix
    }

    Error Code Ranges

    RangeCategoryDescription
    1xxxSessionSession lifecycle errors
    2xxxStorageDatabase and persistence errors
    3xxxCheckpointCheckpoint and rollback errors
    4xxxSyncVersion vector and conflict errors
    5xxxToolTool execution errors
    6xxxAuthAuthentication and authorization errors
    7xxxRate LimitRate limiting and quota errors
    8xxxStreamingSSE stream errors
    9xxxExtensionEnterprise extension errors

    Common Error Codes

    CodeNameHTTPRecovery
    1001SESSION_NOT_FOUND404Create a new session
    1002SESSION_ARCHIVED409Unarchive or create new session
    1003SESSION_LOCKED423Wait for current execution to finish
    2001STORAGE_UNAVAILABLE503Retry after backoff
    2002STORAGE_WRITE_FAILED500Retry; check database connectivity
    3001CHECKPOINT_NOT_FOUND404List checkpoints to find valid ID
    3002CHECKPOINT_EXPIRED410Checkpoints beyond retention are pruned
    4001SYNC_CONFLICT409Re-fetch session state and retry
    4002SYNC_VERSION_MISMATCH409Pull latest version vector first
    5001TOOL_NOT_FOUND404Check tool name against /api/harness/tools
    5002TOOL_EXECUTION_FAILED502Retry; check tool parameters
    5003TOOL_TIMEOUT504Increase timeout or simplify parameters
    6001AUTH_REQUIRED401Provide API key or JWT
    6002AUTH_EXPIRED401Refresh JWT token
    6003INSUFFICIENT_PERMISSIONS403Check API key scopes
    7001RATE_LIMITED429Wait for Retry-After header duration
    7002QUOTA_EXCEEDED429Upgrade plan or wait for quota reset
    8001STREAM_INTERRUPTED502Reconnect and resume from last event
    9001EXTENSION_NOT_FOUND404Check enterprise extension configuration

    Handling Harness Errors

    const response = await fetch(`/api/harness/sessions/${id}/execute`, {
      method: "POST",
      headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
      body: JSON.stringify({ content: message }),
    })
    
    if (!response.ok) {
      const error = await response.json()
      // error.code is the machine-readable code
      // error.recoveryHint suggests how to fix it
      switch (error.code) {
        case "SESSION_LOCKED":
          // Wait and retry
          break
        case "SYNC_CONFLICT":
          // Re-fetch and merge
          break
        case "RATE_LIMITED":
          const retryAfter = response.headers.get("Retry-After")
          // Wait retryAfter seconds
          break
      }
    }

    Automatic Retry (Built-in)

    The SDK automatically retries transient errors (429, 500, 502, 503, 504) with exponential backoff. You only receive these errors after all retries are exhausted.

    const ivy = createIvyClient({
      apiKey: "ivy_...",
      retries: 5, // Try up to 5 times before throwing
    })

    The retry formula: baseDelay * 2^attempt + random_jitter

    Was this page helpful?

    Loading...