API errors and status codes

Every refusal from the Cloudgate API has the same JSON shape. Branch on its status and its code; the message is for people and may change.

Applies to: Hosted and self-hosted

The error body

Every error answer is JSON with these fields:

Field Always What it holds
statusCode Yes The HTTP status, repeated.
error Yes The status in words, such as Conflict.
message Yes What went wrong, in a sentence for people.
path Yes The path you called.
timestamp Yes When the API answered, ISO 8601.
code When named A stable name for the refusal, such as DEPLOYMENT_IN_PROGRESS. Branch on this.
details Validation only One entry per field: path (like aiModel.runtime) and message.
pointer Config refusals Where a Project config kept in a repository lives: repository, path, branch, fileUrl.
output Sometimes A tool’s own output behind a refusal, such as a failed command’s text.

A request that fails validation looks like this:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation failed",
  "details": [{ "path": "name", "message": "Too small: expected string to have >=1 characters" }],
  "path": "/projects",
  "timestamp": "2026-11-12T09:30:00.000Z"
}

An unexpected failure is logged on the instance and answers 500 with no internal detail.

Status codes

Status Meaning What to do
400 The request is malformed: a field is missing or invalid, or the action does not fit the item’s state. Fix the request; details names each field.
401 No credential, or the key is not valid, expired or revoked. Check x-api-key; make a new key if it expired.
402 A payment did not go through (an upgrade on the Hosted instance). Pay in the console, then retry.
403 You are signed in but may not do this. Read the code below; with no code, your role lacks the permission.
404 Nothing with that id in this Organization. Check the id and x-organization-id.
409 It conflicts with the current state: a build is running, a Plan changed, something still depends on it. Read the code; wait or change what it depends on, then retry.
500 Cloudgate failed unexpectedly. Retry later; if it repeats, tell your instance’s admin or support.
503 A Server or the platform host did not answer (code HOST_UNREACHABLE). Check the Server is on and reachable over SSH.

Codes you will meet most

Code Status Meaning
NOT_ORGANIZATION_MEMBER 403 x-organization-id names an Organization you do not belong to.
AGENT_NOT_ALLOWED_HERE 403 An Agent key was sent. Agents use the MCP endpoint, not REST.
PROJECT_ACCESS_NOT_GRANTED, ENVIRONMENT_ACCESS_NOT_GRANTED, SERVICE_ACCESS_NOT_GRANTED 403 Your role allows the action, but you were not granted that Project, Environment or Service.
INSTANCE_AUTHORITY_REQUIRED 403 The route changes the instance itself; only an owner or admin of the instance organization may.
ORGANIZATION_FROZEN 403 Hosted only: the Organization is frozen for an unpaid invoice or a suspension.
PLAN_REQUIRED, ALLOWANCE_FULL 403 Hosted only: the Organization needs a plan, or its plan has no room for another Server or Cloud Environment.
BUSINESS_REQUIRED 403 Hosted only: the feature (SSO, SCIM, custom roles, forward auth) needs the Business plan.
DEPLOYMENT_IN_PROGRESS 409 A build of the Application is running, and an upload would replace the files it reads.
PLAN_STALE, PLAN_NOT_OPEN 409 The Plan changed or was already applied or dismissed since you read it. Check for changes again.
PLAN_DESTROY_NOT_CONFIRMED 409 Applying the Plan would delete something, and the delete was not confirmed by name.
CONFIG_VERSION_STALE 409 A whole-YAML edit named a Config version the Project config has moved on from. Nothing was stored; read the config again and redo the edit.
UPLOAD_CONFLICT 409 Uploading only the changed files: the build host’s files changed since the comparison, or the apply failed there. The previous files are kept; compare again.
ORGANIZATION_LIMIT 403 A new Organization is over the limit: one that pays for itself per person on the Hosted instance, or one per self-hosted instance without an Enterprise license.
PROJECT_CONFIG_REPOSITORY_KEPT, CONFIG_UNREADABLE 409 The Project config is kept in a repository, so change it there; pointer says where.
VARIABLE_IS_LINKED 409 The variable is wired to another Service’s output; change the link, not the value.
VARIABLE_NOT_SET 404 You asked to unset a variable that is not set.
SERVER_HOST_KEY_CHANGED 409 The Server’s SSH host key is not the one recorded. If you reinstalled it, forget the host key and retry.
WORKLOAD_STILL_PRESENT, WORKLOAD_PRESENCE_UNKNOWN 409 A delete could not confirm the containers are gone. Retry, or delete with force=true if the Server is gone for good.
HOST_UNREACHABLE 503 Cloudgate could not reach the Server to do the work.

A 403 with no code, or with an *_ACCESS_NOT_GRANTED code, means the same thing for a person: ask an Owner or Admin. Authentication explains what each role may call, and Members and roles how to change one.

Retrying safely

  • Retry a 500, a 503 or a dropped connection on a read at any time.
  • Before retrying a write, read the item back: a create or a deploy may have landed even though the answer did not reach you, and the API takes no Idempotency-Key.
  • Do not retry a 400, 401, 403 or 404 unchanged; it will fail the same way.
  • A 409 usually clears on its own (a build finishes) or needs a fresh read (a Plan). Wait, read again, then retry.

The overview covers the base URL and headers; each group of endpoints, such as Deployments, lists the refusals of every route.

Questions

Should my script read the message?

Show it to a person, but do not branch on it. The code field is the stable part; the wording of message can change between releases.

What does a 403 with no code mean?

Your role does not hold the permission the route needs. Ask an Owner or Admin of the Organization to change your role or grant it to a custom role you hold.

Why do I get 404 for something I can see in the console?

Check the x-organization-id header. Without it the key acts in your default Organization, where that id does not exist.

Something missing or wrong on this page? Email support@octabyte.io, or start a free trial and try it in the console.