Module: Daytona::Sdk
- Defined in:
- lib/daytona/sdk/errors.rb,
lib/daytona/sdk.rb,
lib/daytona/sdk/version.rb,
lib/daytona/sdk/file_download_patch.rb
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'- ValidationError =
Deprecated.
Use BadRequestError instead. Kept as an alias so existing ‘rescue Daytona::Sdk::ValidationError` blocks keep working.
BadRequestError- 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 =
'0.184.0.alpha.1'
Class Method Summary collapse
-
.api_error_details(error) ⇒ Object
Extract status code, code, source and headers from a raised OpenAPI error.
-
.error_class_for(details) ⇒ Object
Choose the exception class for a parsed error: (source, code) match wins, then HTTP status code, then the base Error.
-
.logger ⇒ Object
The error hierarchy and translation helpers live in ‘sdk/errors.rb`.
- .parse_error_body(response_body) ⇒ Object
- .parsed_message(error) ⇒ Object private
- .string_or_nil(value) ⇒ Object
-
.wrap_error(error, prefix = nil) ⇒ Object
Translate an OpenAPI-client error into the most specific Daytona SDK exception.
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.
224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/daytona/sdk/errors.rb', line 224 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 |
.error_class_for(details) ⇒ Object
Choose the exception class for a parsed error: (source, code) match wins, then HTTP status code, then the base Error.
238 239 240 241 242 243 244 245 246 |
# File 'lib/daytona/sdk/errors.rb', line 238 def self.error_class_for(details) code = details[:code] source = details[:source] if code && source cls = CODE_TO_ERROR[[source, code]] return cls if cls end STATUS_CODE_TO_ERROR.fetch(details[:status_code], Error) end |
.logger ⇒ Object
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.
51 |
# File 'lib/daytona/sdk.rb', line 51 def self.logger = @logger ||= Logger.new($stdout, level: Logger::INFO) |
.parse_error_body(response_body) ⇒ Object
248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/daytona/sdk/errors.rb', line 248 def self.parse_error_body(response_body) return {} if response_body.nil? || response_body.empty? data = JSON.parse(response_body) return {} unless data.is_a?(Hash) { message: string_or_nil(data['message']) || string_or_nil(data['error']), code: string_or_nil(data['code'] || data['error_code']), source: string_or_nil(data['source']) } rescue JSON::ParserError {} end |
.parsed_message(error) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
264 265 266 267 268 269 |
# File 'lib/daytona/sdk/errors.rb', line 264 def self.(error) return nil unless API_ERROR_CLASSES.any? { |c| error.is_a?(c) } return nil unless error.respond_to?(:response_body) parse_error_body(error.response_body)[:message] end |
.string_or_nil(value) ⇒ Object
271 272 273 |
# File 'lib/daytona/sdk/errors.rb', line 271 def self.string_or_nil(value) value.is_a?(String) && !value.empty? ? value : nil end |
.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.
208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/daytona/sdk/errors.rb', line 208 def self.wrap_error(error, prefix = nil) if error.is_a?(Error) = prefix ? "#{prefix}: #{error.}" : error. return error.class.new(, status_code: error.status_code, code: error.code, source: error.source, headers: error.headers) end details = api_error_details(error) = (error) || error. = prefix ? "#{prefix}: #{}" : error_class_for(details).new(, **details.slice(:status_code, :code, :source, :headers)) end |