Skip to content

Errors

Every API error has the same shape, and docs_url points at the matching section of this page. The exception is a path that exists asked with a method it doesn't take: that's a 405 with no body, from before our code runs.

{
  "error": {
    "code": "limit_reached",
    "message": "The Free plan runs 1 machine at a time, and dev is already running. Suspend one or upgrade.",
    "retryable": false,
    "retry_after_seconds": null,
    "docs_url": "https://tryquivvo.com/docs/errors#limit_reached",
    "request_id": "req_...",
    "owner_action": { "url": "https://tryquivvo.com/app/billing", "message": "Upgrade from the Free plan to run more machines at once." }
  }
}
Field What to do with it
code Branch on this. The message can change
retryable, retry_after_seconds When retryable is true, wait that long and send the same request again
request_id Quote it when you report a problem. It's also the x-request-id header
owner_action Something only the workspace's owner can do, signed in on the dashboard. Pass on message and url: an API key can't do it

The CLI turns these into exit codes. Under --json every error is one document on stdout, with the same fields plus exit_code, status and hint. The MCP server returns the same fields as JSON text with isError set.

bad_request

HTTP 400. CLI exit 2. Don't retry as it is.

The request is wrong: a bad field, a size that isn't allowed, a missing X-Confirm-Delete header, or an upload over 4 MB. The message says what to change.

unauthorized

HTTP 401. CLI exit 3. Don't retry as it is.

There's no key, or it's invalid or was revoked. Sign in again with quivvo login --agent --no-wait --json, or check QUIVVO_API_KEY. See agent sign-up.

forbidden

HTTP 403. CLI exit 3. Don't retry as it is.

This key doesn't have the scope, a read-only key asked for a path it can't read (/proc, /sys, /dev, /run or the daemon's own state), the route needs someone signed in on the dashboard, as billing does, or a signed-in browser's request came from another site. GET /api/v1/whoami lists the scopes a key has. owner_action says what the owner can do.

not_found

HTTP 404. CLI exit 4. Don't retry as it is.

There's no such machine, snapshot, job or file in this workspace. quivvo ls shows the machines it has.

conflict

HTTP 409. CLI exit 75 when retryable, otherwise 1. From exec, run and sh, 125.

The name is taken, the machine is between states or still being created, its CPU or memory can't change while it runs, a snapshot isn't ready, a disk is still being copied from what you're deleting, or an Idempotency-Key was reused for a different request, including the same route with a different body. When retryable is true, the machine is between states and will settle: try again. Otherwise the message says what to change.

limit_reached

HTTP 403. CLI exit 5. Don't retry as it is.

A plan limit: machines running at once, machines kept, size, disk, snapshots, how long a machine may stay awake, active keys, webhooks, or published ports on a machine. The message names the limit and what's in the way. Make room with what you're allowed to do: suspend or delete a machine, or delete a snapshot. The CLI's hint names the commands. A request that's wrong in itself, such as a bad name or a name already taken, gets that error first and never this one. Upgrading is for the owner: pass on owner_action.

insufficient_credits

HTTP 402. CLI exit 5. Don't retry as it is.

The credit balance is empty, so machines can't run. Only the owner can add credit, on the dashboard: pass on owner_action. API keys can't reach billing.

queued

HTTP 403. CLI exit 5. Don't retry as it is.

This workspace is waiting in the queue, so it can't create or fork machines yet. The message gives its place. Only the owner can move it: pass on owner_action, which holds their invite link. Each person who signs up with the link moves them up 10 places, and a paid plan skips the queue. quivvo queue and GET /queue show the same.

machine_not_running

HTTP 409. CLI exit 75 when retryable, otherwise 1, or 125 from exec, run and sh.

The machine isn't running, and nothing ran. With retry_after_seconds it's on its way up: try again, as the CLI does by itself. Without it, it stays down until asked: run quivvo start or quivvo resume, or for a machine in failed, quivvo restart. The MCP server's read tools answer this for any machine that isn't running, because they don't wake machines, and so does the REST API for a key with no machines:write.

provider_error

HTTP 502. CLI exit 75 when retryable, otherwise 1. From exec, run and sh, 125.

The machine's host, or its daemon, didn't do what was asked. The command may or may not have run, so check before repeating anything that changes things. quivvo logs shows what's known about a machine, whatever its state.

A snapshot or fork that the provider won't copy ends here too. In that case nothing was created, and the source is untouched.

capacity

HTTP 503. CLI exit 75. Retry after retry_after_seconds.

There's no room right now, on our side or the provider's. On a create, nothing was created: try another region with --region, or try again in a few minutes. On a start or resume, the machine and its disk are where they were, and no other host in its region had room either: try again in a few minutes.

rate_limited

HTTP 429. CLI exit 75. Retry after retry_after_seconds.

Too many requests, such as more than 30 feedback reports in an hour, more than 600 commands or 1,200 changes of any kind a minute in a workspace, more machines created in an hour than a plan allows (60 on Free), or too many sign-ins started from one address. Nothing happened. Wait and send it again. A sign-in that's already pending doesn't count: run the same login again and it reuses its code.

internal

HTTP 500. CLI exit 75 when retryable, otherwise 1. From exec, run and sh, 125.

Something went wrong on our side. The request may or may not have taken effect, so check first if repeating it would matter. If it keeps happening, report it with the request_id: quivvo feedback "what happened".

authorization_pending

HTTP 400, while polling POST /api/v1/auth/device/token. quivvo login --agent --no-wait exits 75.

The owner hasn't decided yet. Try again later, no sooner than every interval seconds. An agent should end its turn rather than wait.

access_denied

HTTP 400, while polling. quivvo login exits 77.

The owner refused this sign-in. Ask them before trying again. Nothing was created.

expired_token

HTTP 400, while polling. quivvo login exits 76.

The code expired before anyone approved it, or this sign-in was already completed. Agent codes last 24 hours and CLI codes 15 minutes. Run the command again for a new code.

What other codes can the CLI report?

Under --json, a failure that never reached the API has a code of its own:

Code Exit Meaning
usage 2 The command line was wrong. quivvo help --json lists every command and flag
not_signed_in 3 There's no key. The hint names the sign-in command
no_terminal 3 quivvo login needs a person at a terminal. The hint says what to run instead
network_error 75, 1 or 125 The API couldn't be reached. 75 means nothing happened; 1 or 125 means it may have
timeout 124 A wait ran out. What you were waiting for keeps going
agent_not_installed, agent_not_signed_in 3 quivvo agent prompt: the message gives the exact fix
confirmation_required 2 Something destructive needs --yes when there's no terminal to ask on
setup_failed 1 create --wait-setup: the script failed, and the machine is still there and billing. The hint has its log and how to delete it
machine_failed 1 A machine being waited for went to failed. quivvo logs shows what's known
unexpected_state 1 A machine being waited for settled in a state nobody asked for
snapshot_failed 1 snapshot save: the copy didn't finish
stream_lost 125 exec: the stream ended before the command did, so its result is unknown. quivvo history shows what's known
command_lost 125 run: the machine restarted while the command ran, so its result is unknown
nothing_to_push 2 push: every file in the directory is left out. The hint says how to send them
tar_failed 1 cp or push: the local tar failed
no_desktop 1 desktop: the machine's image has none. A new machine on the universal template has one
bad_config 1 mcp init: an existing config file can't be read, and it wasn't touched
client_failed 1 mcp init: the client's own command failed. The hint has the command to run yourself
no_session 1 agent prompt --continue: that run has no session to carry on from
preflight_failed 1 agent prompt: the check before starting failed. The message says why

exec, run, ssh, jobs wait and jobs logs -f pass on the remote command's exit code, which can be any of these numbers too. Under --json, the error key is what tells them apart.

Updated 8 November 2026

Give your agent a computer

npx quivvo@latest sh
Get a free VM