Cubicle

Errors

The Cubicle HTTP API error envelope with code and message, every error code the public routes return (invalid_request, unauthenticated, forbidden, not_found, conflict, idempotency_conflict, rate_limited, capacity and more) with its HTTP status and what to do, conflict messages, and which errors are safe to retry.

Every error is a JSON object with an error member and a matching HTTP status:

{
  "error": {
    "code": "conflict",
    "message": "a box named job-1 already exists"
  }
}
  • code is machine-readable. Branch on it, not on message.
  • message is for people. For invalid_request, it usually names the field that failed and why.
  • Some errors add fields to error. rate_limited, and blocked when the block has an end, add retryAfterSeconds, and send the same number of seconds in a Retry-After header (example).

Treat a response without this envelope, such as a 502 or 504 with an HTML body, like a lost connection: the request may or may not have reached the API.

Each endpoint page lists the errors that route can return, under its response statuses. The SDK raises them as CubicleApiError, with the same status, code and message; see Errors and retries.

Error codes

These are the codes the routes in the endpoint reference return.

CodeStatusMeaningWhat to do
invalid_path400The URL, or the percent-encoding of a path segment, is malformed.Fix the URL. Encode the slash in ORG/NAME as %2F.
invalid_json400The body is not valid JSON.Send a JSON body with Content-Type: application/json.
invalid_request400The body, a parameter or a header fails validation. See Validation errors.Fix what message names. Do not retry unchanged.
invalid_key400Add an SSH key: the key is not a valid ssh-ed25519 public key.Send one line from ~/.ssh/id_ed25519.pub.
authorization_pending400Exchange a device code: nobody has authorized or denied the sign-in yet.Poll again after interval seconds.
access_denied400Device sign-in: the person chose Deny.Stop polling.
expired_token400Device sign-in: the code expired, 600 s after it was issued.Stop polling, and start a new sign-in.
invalid_grant400Device sign-in: the code is unknown, or was already exchanged for a session.Stop polling.
unauthenticated401The bearer token is missing, malformed, expired or revoked. See Authentication errors.Fix the header, or get a new token.
forbidden403You lack the role or the grant. message says which, such as an explicit box grant is required or box grant or organization admin role required.Ask an owner or admin of the organization for a grant or a role. See Organizations and access.
insufficient_scope403A read API key sent a request other than GET.Use a write key.
api_key_not_allowed403The route needs a sign-in session, and an API key was sent.Use a sign-in session.
box_create_disabled403The organization may not create Boxes. Personal organizations start this way.Create the Box in an organization whose boxCreateAllowed is true in Get the caller, or ask a Cubicle operator to allow it.
blocked403Your client address is blocked, after repeated rate-limit refusals or by an operator.Send nothing until Retry-After seconds have passed. See Rate limits.
not_found404The route or the resource does not exist, or you may not see it: it is in an organization where you are not an active member, outside an API key's organization, or a Box that is being deleted.Check the path, the reference and the organization. After a delete, a 404 for the Box is expected.
method_not_allowed405The path exists, but not with this method.Check the method on the endpoint page.
conflict409The request conflicts with the resource's current state. message says how; see Conflicts.Depends on the message.
ambiguous_box409A bare NAME matches Boxes in several of your organizations.Use the Box's ID, ORG/NAME or ?org=.
idempotency_conflict409The Idempotency-Key was already used for this route with a different body, or, for exec, snapshot and restore, with another Box.Use a new key, or send the original body. See Idempotency keys.
last_owner409Remove a member: the member is the organization's only active owner.Make another member an owner first.
payload_too_large413The body is larger than 64 KiB.Send less. To get a large script or file into a Box, see Move files into and out of a Box.
rate_limited429Your request budget, or a sign-in limit, is spent. retryAfterSeconds and Retry-After say when to retry.Wait Retry-After seconds before any further request, then retry. See Rate limits.
internal500The API failed unexpectedly.Retry if the request is safe to repeat.
capacity503No Node can place the Box when it is created: none has room, or the Node that holds its source snapshot is unavailable or full. A free Box (pooled: true) also gets it when its Node has no room to start it. Nothing was created or started.Retry later, or ask for a smaller Box.
logins_paused503Device sign-in: sign-in is paused, so no session can be issued now.Try again later.

Routes that only the Dashboard and the CLI use, such as the private network and the desktop console, have more codes. They are not listed here.

Validation errors

400 invalid_request means the request failed validation. message names the field and the problem. Common causes:

  • A required field is missing, or a field has the wrong type.
  • A value is out of range, such as a Box size or an exec timeoutMs under 100 ms.
  • A {user}, {session} or {key} path segment is not a UUID.
  • An Idempotency-Key is not 1 to 200 characters.
  • A create names both baseImage and snapshotId.
  • A create from a snapshot asks for a smaller disk than the snapshot's.

Fix what message names. Do not retry the request unchanged.

Conflicts

409 conflict covers several situations. These are its messages on the public routes:

MessageReturned byWhat to do
a box named job-1 already existsCreate a BoxChoose another name, or delete the other Box.
service account ci already existsCreate a service accountChoose another name.
resource already existsCreating an API key whose name is taken, adding an SSH key you already have, or two requests racing to create the same thingUse another name, or read the existing resource.
box is not runningRun a commandStart the Box and wait for ssh.ready.
stop the box before taking a snapshotTake a snapshotStop the Box and wait for stopped at the current generation.
stop the box before restoring a snapshotRestore a BoxStop the Box and wait for stopped at the current generation.
snapshot is not completeCreate a Box from a snapshot, restoreWait until the snapshot's operation is done. A failed snapshot cannot be used.
only a running box can hibernateHibernate a BoxHibernate only a Box whose desired state is running.
the box requires an explicit Start after a host rebootHibernateStart the Box.
a snapshot or restore is in progress for this boxStart, stop, hibernate, deleteWait until the snapshot or restore operation ends, then retry.
box job-2 is still being created from a snapshot of this boxDelete a BoxRetry once the named Box has finished copying the snapshot.
the box changed while starting; try againStart a free Box (pooled: true)Retry at once.

Which errors are safe to retry

ResponseRetry?
429 rate_limitedYes, after Retry-After seconds. The request did nothing.
403 blockedOnly after Retry-After seconds. Every request before then is refused.
503 capacity, 503 logins_pausedYes, later. Nothing was done.
409 conflict for a snapshot or restore in progress, a Box still being created from a snapshot, or a free Box that changed while startingYes, once the cause has passed.
400 authorization_pendingYes: this is how you poll a device sign-in.
500 internal, a timeout, a lost connection or a response without the envelopeOnly when repeating the request is safe; see below.
Any other 4xxNo. Change the request, the credentials or the Box's state first.

After a 500, a timeout or a lost connection, the request may or may not have taken effect. Repeating it is safe for:

  • any GET
  • create, exec, snapshot and restore sent again with the same Idempotency-Key
  • start, stop and hibernate, which a repeat leaves in the same desired state. A repeated start or stop advances the Box's generation again.
  • delete by ID, where a 404 on the repeat means the first one went through

The SDK retries 429, 502, 503 and 504 for you; see Errors and retries.

On this page