better/compute

Errors

Every stable error code the API, the SDK and the CLI surface, with its HTTP status.

Errors answer { "error": { "code", "message", "retryAfterMs"?, "details"? } }. Codes are stable; messages are not.

CodeHTTP statusMeaning
UNAUTHENTICATED401The request carries no credential, or IAM does not accept the one it carries.
ACCESS_DENIED403IAM decided the call's action @ resource and denied it.
CONFIRMATION_REQUIRED403The caller is an agent acting for a person, and that person must confirm the request first.
NOT_FOUND404The route, or the object the input names, does not exist or is not visible to the caller.
INVALID_INPUT400The body failed validation: a missing or unknown field, a wrong type, or a value outside its constraints.
INVALID_STATE409The object exists but is in a state that does not allow the call, such as uncordoning a node being deleted or extending a released reservation.
CONFLICT409The call raced a concurrent change, or reuses an idempotencyKey for a different request, or names something that already exists.
CAPACITY_UNAVAILABLE409No placement satisfies the request now: there are not enough free GPUs, or none that match its constraints, in the pools it may use.
QUOTA_EXCEEDED409The request would take the tenant or project past a quota, or past a per-tenant limit such as the number of webhooks.
SPEND_LIMIT_REACHED402An IAM budget covering this request is spent, and the pool refuses new work when a budget is exceeded.
UNSUPPORTED422The request is valid, but the driver, provider or deployment it lands on cannot do it: a provider with no power control, an instance that cannot be resized in place, or a deployment with no SSH CA.
UPGRADE_REQUIRED426The peer speaks a protocol version older than the server's minimum.
RATE_LIMITED429Too many requests of this kind, from the caller or to a provider behind the call.
DRIVER_ERROR502A driver, a node command or a site agent failed, or answered with something compute cannot trust: a BMC operation that failed, an unattested result, or firmware and BIOS settings that did not take.
PROVIDER_ERROR502A VPS or bare-metal provider's API refused or failed the call.
INVALID_CONFIG500The deployment is configured wrongly, for example an option out of range or a module that needs another one.
NOT_IMPLEMENTED501The method or feature is planned for a later phase and not built in this release.
CSRF_REJECTED403A POST lacks content-type: application/json or the X-Better-Compute: 1 header, or a cookie-authenticated request has no Origin.
UNTRUSTED_ORIGIN403A cookie-authenticated request, or a tunnel's WebSocket upgrade, came from an Origin other than the deployment's own.
METHOD_NOT_ALLOWED405The HTTP method is not accepted on this path.
PAYLOAD_TOO_LARGE413The request body is larger than the server accepts.
INTERNAL_ERROR500An unexpected failure on the server.
MISSING_DEPENDENCY500An optional package or service the deployment needs for this call is not installed or not configured, such as PGlite for an embedded database or a remote IAM endpoint.
CONFIG_DRIFT409The fleet changed after the plan was made, so fleet.apply refused a plan whose planHash no longer matches.
UNAVAILABLE503A dependency the request needs is unreachable for now: the secret store's KMS, a node's gateway, or remote IAM.
TENANT_SUSPENDED403The IAM tenant is suspended, so its mutations are refused, or deleted, so every call is refused.

UNAUTHENTICATED

HTTP 401.

The request carries no credential, or IAM does not accept the one it carries.

Send a valid IAM session or API key. An expired key or a revoked session answers the same way; the message does not say which.

ACCESS_DENIED

HTTP 403.

IAM decided the call's action @ resource and denied it.

Callers outside the input tenant (and outside the root tenant) are refused before any database access. Grant the action in IAM, or call as an identity that holds it. See Actions and resources.

CONFIRMATION_REQUIRED

HTTP 403.

The caller is an agent acting for a person, and that person must confirm the request first.

details carries confirmationId, the action and resource, and expiresAt when IAM set one. Nothing was changed. Once the person confirms, retry with the same idempotencyKey. See Delegated confirmation.

NOT_FOUND

HTTP 404.

The route, or the object the input names, does not exist or is not visible to the caller.

Lookups are scoped to the input tenantId, so an id that belongs to another tenant is not found.

INVALID_INPUT

HTTP 400.

The body failed validation: a missing or unknown field, a wrong type, or a value outside its constraints.

Unknown fields are refused, never ignored. The Input table of each method in the API reference lists every accepted field.

INVALID_STATE

HTTP 409.

The object exists but is in a state that does not allow the call, such as uncordoning a node being deleted or extending a released reservation.

Read the object again and act on its current state. Retrying unchanged fails the same way.

CONFLICT

HTTP 409.

The call raced a concurrent change, or reuses an idempotencyKey for a different request, or names something that already exists.

A concurrent change is safe to retry after reading the object again. A reused key with a different body is not: send a new key for a new request.

CAPACITY_UNAVAILABLE

HTTP 409.

No placement satisfies the request now: there are not enough free GPUs, or none that match its constraints, in the pools it may use.

Retry later, relax the constraints, or book a later window. See Placement.

QUOTA_EXCEEDED

HTTP 409.

The request would take the tenant or project past a quota, or past a per-tenant limit such as the number of webhooks.

Release something, or raise the quota with quotas.set. See Quotas and usage.

SPEND_LIMIT_REACHED

HTTP 402.

An IAM budget covering this request is spent, and the pool refuses new work when a budget is exceeded.

details names the budget (budgetId, name) when IAM reports it. See Billing and usage.

UNSUPPORTED

HTTP 422.

The request is valid, but the driver, provider or deployment it lands on cannot do it: a provider with no power control, an instance that cannot be resized in place, or a deployment with no SSH CA.

UPGRADE_REQUIRED

HTTP 426.

The peer speaks a protocol version older than the server's minimum.

A daemon below proto_min is welcomed but receives only daemon.upgrade until it runs a supported version. See Protocol.

RATE_LIMITED

HTTP 429.

Too many requests of this kind, from the caller or to a provider behind the call.

Wait retryAfterMs when the error carries it, then retry. The TypeScript client does this once when created with retryRateLimited (waits up to 5 seconds by default).

DRIVER_ERROR

HTTP 502.

A driver, a node command or a site agent failed, or answered with something compute cannot trust: a BMC operation that failed, an unattested result, or firmware and BIOS settings that did not take.

The message names the step; details may carry the driver's own code (driverCode).

PROVIDER_ERROR

HTTP 502.

A VPS or bare-metal provider's API refused or failed the call.

The message carries the provider's reason. Background work such as instance bootstraps retries it; a direct call does not.

INVALID_CONFIG

HTTP 500.

The deployment is configured wrongly, for example an option out of range or a module that needs another one.

This describes the server, not the request, so it answers 500. Fix the configuration and restart.

NOT_IMPLEMENTED

HTTP 501.

The method or feature is planned for a later phase and not built in this release.

details names the feature and the phase that delivers it. See the roadmap.

CSRF_REJECTED

HTTP 403.

A POST lacks content-type: application/json or the X-Better-Compute: 1 header, or a cookie-authenticated request has no Origin.

Browsers cannot send that header cross-site without a preflight, so it stops cross-site request forgery. Clients built on the SDK send it.

UNTRUSTED_ORIGIN

HTTP 403.

A cookie-authenticated request, or a tunnel's WebSocket upgrade, came from an Origin other than the deployment's own.

METHOD_NOT_ALLOWED

HTTP 405.

The HTTP method is not accepted on this path.

API methods are POST only; GET serves /health and /.well-known/better-compute; tunnels need a WebSocket upgrade.

PAYLOAD_TOO_LARGE

HTTP 413.

The request body is larger than the server accepts.

INTERNAL_ERROR

HTTP 500.

An unexpected failure on the server.

The server logs it with the request id (x-request-id); quote that id when reporting it.

MISSING_DEPENDENCY

HTTP 500.

An optional package or service the deployment needs for this call is not installed or not configured, such as PGlite for an embedded database or a remote IAM endpoint.

Like INVALID_CONFIG, it describes the deployment, so it answers 500.

CONFIG_DRIFT

HTTP 409.

The fleet changed after the plan was made, so fleet.apply refused a plan whose planHash no longer matches.

Plan again and review the new plan. --fail-on-drift in the CLI uses the same code. See Fleet configuration.

UNAVAILABLE

HTTP 503.

A dependency the request needs is unreachable for now: the secret store's KMS, a node's gateway, or remote IAM.

Nothing was changed. Retry after retryAfterMs.

TENANT_SUSPENDED

HTTP 403.

The IAM tenant is suspended, so its mutations are refused, or deleted, so every call is refused.

details carries the tenantId and its state. A suspension or deletion also covers the tenant's descendants, and root-tenant callers are exempt. Reads still work in a suspended tenant. See Tenancy.

Was this page helpful?

Better Compute is created by Sean Filimon

Last updated

On this page