Module: Daytona::Sdk

Defined in:
lib/daytona/sdk/errors.rb,
lib/daytona/sdk.rb,
lib/daytona/sdk/version.rb,
lib/daytona/sdk/deprecated.rb,
lib/daytona/sdk/file_download_patch.rb,
sig/daytona/sdk.rbs

Overview

rubocop:disable Metrics/ModuleLength

Defined Under Namespace

Modules: FileDownloadPatch Classes: A11yUnavailableError, AuthenticationError, BadGatewayError, BadRequestError, CommandAlreadyCompletedError, ConflictError, ConnectionError, ConnectionTimeoutError, Error, FileAccessDeniedError, FileNotFoundError, ForbiddenError, GitAuthFailedError, GitBranchExistsError, GitBranchNotFoundError, GitDirtyWorktreeError, GitMergeConflictError, GitPushRejectedError, GitRepoNotFoundError, GoneError, InternalServerError, LspServerNotInitializedError, NotFoundError, ProcessExecutionTimeoutError, ProcessNotFoundError, RateLimitError, RecordingFfmpegNotFoundError, RecordingStillActiveError, ServerError, ServiceUnavailableError, SessionEndedError, TimeoutError, UnprocessableEntityError

Constant Summary collapse

API_ERROR_CLASSES =

ApiError classes raised by the generated OpenAPI clients. Kept here so the error module can resolve them without depending on sdk.rb.

[DaytonaApiClient::ApiError, DaytonaToolboxApiClient::ApiError].freeze
SOURCE_API =

Wire-format source values set by the translation layer when a Daytona service stamps them on the wire envelope. nil source means the response did not carry a structured envelope (treat as opaque).

'DAYTONA_API'
SOURCE_DAEMON =
'DAYTONA_DAEMON'
SOURCE_PROXY =
'DAYTONA_PROXY'
STATUS_CODE_TO_ERROR =

Routing tables

{
  400 => BadRequestError,
  401 => AuthenticationError,
  403 => ForbiddenError,
  404 => NotFoundError,
  408 => TimeoutError,
  409 => ConflictError,
  410 => GoneError,
  422 => UnprocessableEntityError,
  429 => RateLimitError,
  500 => InternalServerError,
  502 => BadGatewayError,
  503 => ServiceUnavailableError,
  504 => TimeoutError
}.freeze
CODE_TO_ERROR =

(source, code) tuple → exception class. Resolved BEFORE the status code, so a server-stamped domain code always wins over the generic status class.

{
  # Daemon: git
  [SOURCE_DAEMON, 'GIT_AUTH_FAILED'] => GitAuthFailedError,
  [SOURCE_DAEMON, 'GIT_REPO_NOT_FOUND'] => GitRepoNotFoundError,
  [SOURCE_DAEMON, 'GIT_BRANCH_NOT_FOUND'] => GitBranchNotFoundError,
  [SOURCE_DAEMON, 'GIT_BRANCH_EXISTS'] => GitBranchExistsError,
  [SOURCE_DAEMON, 'GIT_PUSH_REJECTED'] => GitPushRejectedError,
  [SOURCE_DAEMON, 'GIT_DIRTY_WORKTREE'] => GitDirtyWorktreeError,
  [SOURCE_DAEMON, 'GIT_MERGE_CONFLICT'] => GitMergeConflictError,

  # Daemon: filesystem
  [SOURCE_DAEMON, 'FILE_NOT_FOUND'] => FileNotFoundError,
  [SOURCE_DAEMON, 'FILE_ACCESS_DENIED'] => FileAccessDeniedError,

  # Daemon: LSP
  [SOURCE_DAEMON, 'LSP_SERVER_NOT_INITIALIZED'] => LspServerNotInitializedError,

  # Daemon: process / session
  [SOURCE_DAEMON, 'PROCESS_EXECUTION_TIMEOUT'] => ProcessExecutionTimeoutError,
  [SOURCE_DAEMON, 'PROCESS_NOT_FOUND'] => ProcessNotFoundError,
  [SOURCE_DAEMON, 'SESSION_ENDED'] => SessionEndedError,
  [SOURCE_DAEMON, 'COMMAND_ALREADY_COMPLETED'] => CommandAlreadyCompletedError,

  # Daemon: computer-use
  [SOURCE_DAEMON, 'A11Y_UNAVAILABLE'] => A11yUnavailableError,
  [SOURCE_DAEMON, 'RECORDING_STILL_ACTIVE'] => RecordingStillActiveError,
  [SOURCE_DAEMON, 'RECORDING_FFMPEG_NOT_FOUND'] => RecordingFfmpegNotFoundError
}.freeze
VERSION =

Returns:

  • (String)
'0.201.0'
ValidationError =
Deprecated.

Use BadRequestError instead. Kept as an alias so existing rescue Daytona::Sdk::ValidationError blocks keep working.

BadRequestError

Class Method Summary collapse

Class Method Details

.api_error_details(error) ⇒ Object

Extract status code, code, source and headers from a raised OpenAPI error. Returns an empty hash when the error is not one of the generated client types.



220
221
222
223
224
225
226
227
228
229
230
# File 'lib/daytona/sdk/errors.rb', line 220

def self.api_error_details(error)
  return {} unless API_ERROR_CLASSES.any? { |c| error.is_a?(c) }

  data = parse_error_body(error.respond_to?(:response_body) ? error.response_body : nil)
  {
    status_code: error.respond_to?(:code) ? error.code : nil,
    code: data[:code],
    source: data[:source],
    headers: error.respond_to?(:response_headers) ? error.response_headers : nil
  }
end

.loggerObject

The error hierarchy and translation helpers live in sdk/errors.rb. This file just provides cross-cutting bits that need to be loaded alongside them.



58
# File 'lib/daytona/sdk.rb', line 58

def self.logger = @logger ||= Logger.new($stdout, level: Logger::INFO)

.wrap_error(error, prefix = nil) ⇒ Object

Translate an OpenAPI-client error into the most specific Daytona SDK exception. Accepts an optional prefix that's prepended to the message for context (e.g. "Failed to create sandbox"). When error is already an Sdk::Error (e.g. raised by the streaming transfer helpers for cancel/timeout), its class is preserved and only the message is prefixed.



204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/daytona/sdk/errors.rb', line 204

def self.wrap_error(error, prefix = nil)
  if error.is_a?(Error)
    message = prefix ? "#{prefix}: #{error.message}" : error.message
    return error.class.new(message, status_code: error.status_code, code: error.code,
                                    source: error.source, headers: error.headers)
  end

  details = api_error_details(error)
  base_message = parsed_message(error) || error.message
  message = prefix ? "#{prefix}: #{base_message}" : base_message
  error_class_for(details).new(message, **details.slice(:status_code, :code, :source, :headers))
end