Error reference
Every error is plain JSON with a machine code, plus a human detail
where it helps:
{"error": "version-mismatch", "detail": "..."}
Some errors carry extra keys — unknown-node echoes the unresolved
entry under name, ambiguous-cluster lists the candidate clusters,
rate-limited carries retry_after_s. The OpenAPI contracts are the
authority; this page is the tour.
Auth and addressing
| Code |
Status |
Meaning |
Fix |
unauthorized |
401 |
missing, malformed, expired, or revoked token |
mint or re-issue on the console's API Keys page |
session-required |
403 |
an API token on a console-only action: the volume delete, raising or clearing the spend limit, or loosening auto reload (enabling it, raising its amount, lowering its threshold); every token is refused |
sign in to the console and use the Storage or Billing page |
reserved-arrangement |
403 |
a billing write for an organization whose credits the platform team manages |
contact the platform team |
not-found |
404 |
no cluster of the right kind matches the token, the {org} in the path is not the token's organization, or a node, pod or volume named on a cluster page read is not in your organization |
check the token's binding; a VM-bound token is refused on the k8s surfaces and vice versa |
ambiguous-cluster |
409 |
org-wide token, several clusters of that kind; or the public onboarding path (access.nationalcompute.com/api/onboard/<name>) when more than one cluster carries the name |
pass cluster (query on GETs, body on writes); on the onboarding path fetch the kubeconfig by token, GET /api/k8s/cluster/kubeconfig |
Validation (422)
| Code |
Meaning |
price-precision |
prices are USD, whole cents — at most 2 decimals |
bid-too-low |
a declare too low to ever clear the market that would acquire capacity; check the market feed for what wins and raise the price. Scale-downs are never price-gated (a k8s limit price of 0 always withdraws) |
no-ssh-keys |
a VM capacity raise with no registered ssh key — the node would be unreachable (register one first) |
bad-request |
malformed body; the detail says exactly what — including a non-multiple max_gpus (whole nodes only, never rounded) and the retired per-node field spellings (the detail gives the conversion) |
card-cap |
a checkout above what a card can still carry this window; the summary's card_window_remaining_usd says how much that is, larger amounts go by wire transfer |
confirmation-mismatch |
a volume delete whose confirm is not the volume's storage name (its name field, shown under the label; the label is refused); nothing is destroyed (shared storage volumes) |
Concurrency and state (409)
| Code |
Meaning |
version-mismatch |
your expected_version no longer matches — re-read, reconcile, retry (conventions) |
unknown-node |
a release or swap entry resolves to no node you hold; the entry is echoed under name, and nothing is written |
static-posture |
a max_gpus raise on a cluster not under market management — nothing would fill the new capacity; lowering and release still work |
swap-disabled, cluster-gated, node-pinned |
a swap the platform can't take right now — the surface isn't enabled for your site, the cluster is gated, or the node is pinned; the swap is refused whole |
volume-attached |
a delete of a shared volume that is attached to a live cluster; delete the cluster first (the volume detaches with it and is preserved by default) or opt to delete the storage with the cluster |
volume-held |
a delete of a preserved volume a node still holds; retry in a few minutes, contact support if it persists |
cluster-not-ready |
a cluster page read or the kubeconfig download on a cluster that is still being built or is not ready; retry |
card-window |
a checkout while the rolling card cap is spent (card_window_remaining_usd is 0); wait for payments to age out of the window, or pay by wire transfer |
no-purchases |
the payment portal before the first purchase; nothing to manage yet |
no-card |
enabling auto reload with no card on file; the setup page saves one |
| Code |
Status |
Meaning |
rate-limited |
429 |
faster than the per cluster write cadence, or more than 300 requests in one minute with this token; wait retry_after_s |
purchases-unavailable |
503 |
self serve purchases are off, so a billing write that needs them is refused; load credits through the console's Billing page or contact the platform team |
station-unavailable, — |
503 |
temporary platform condition — reads keep serving, retry writes later |
Admission denials (Kubernetes)
These denials arrive from your cluster's API server at kubectl apply
time, not from this HTTP API — see
launch admission and
the max cluster size:
| Denial |
Meaning |
JobSizeTooSmall |
a pod template's GPU request is not a multiple of gpus_per_node on a cluster without packing onto the base load block; GPU workloads on the market occupy full nodes |
JobSizeNotNodeAligned |
on a cluster with packing onto the base load block enabled a pod template requests more GPUs than one node and not a whole number of nodes; pods smaller than one node and whole node multiples are admitted there |
BalanceTooLow |
the org balance does not cover two hours of the job at the current limit price; the message names the required and current balance |
StationOwned |
an edit of a Kueue object the platform owns — the ClusterQueue market, its flavors, admission check, request config and priority classes — these are read-only to cluster users; the max cluster size is set by the platform |
BalanceTooLow is also a queue reason: the market re-checks the same
two hours at every tick while the request waits, and a request the
balance can no longer fund stays pending under that reason — never
refused — until a top-up (queue events).
Handling advice
- Treat the machine code as the contract; the
detail text can change.
- On
409 version-mismatch, always re-read before retrying — the state
that moved under you may change what you want to write.
- On
429, respect retry_after_s rather than tight-looping; writes
are paced per cluster, so a second client on the same cluster shares
your budget.