Atlas CMS

Error Handling

The response envelope, HTTP status codes, and how to handle errors from the Atlas API (Public and Management).

Error Handling

Every Atlas API response — success or error — is returned as JSON wrapped in a consistent envelope. This applies to both the Public API (/api/v1/public/*) and the Management API (/api/v1/manage/*).

Response Envelope

FieldTypePresent whenDescription
successbooleanAlwaystrue for successful requests, false for errors.
messagestringAlwaysHuman-readable summary of the result.
dataanySuccess onlyThe payload (object or array).
metaobjectList endpointsPagination info (total_data, current_page, page_size, total_pages, next_cursor).
codestringErrors onlyMachine-readable error code (e.g. UNAUTHORIZED).
errorsobjectValidation errorsField-level detail (e.g. { "type": ["required"] }).
traceIdstringErrors onlyRequest trace ID — include this when reporting an issue.

HTTP Status Codes

CodeMeaning
200OK — request succeeded.
400Bad Request — malformed parameters (e.g. invalid cursor, page out of range) or validation error.
401Unauthorized — X-API-Key header is missing, empty, or wrong key class (e.g. atlas_live_ used on management endpoint).
403Forbidden — key is valid but lacks required scope or RBAC permission.
404Not Found — entry, page, or media file does not exist, or belongs to a different workspace.
429Too Many Requests — rate limit exceeded; back off and retry.
500Internal Server Error — something went wrong on Atlas's side.

Example Responses

200 — Success
{
  "success": true,
  "message": "Success",
  "data": { "slug": "getting-started-with-headless-cms", "status": "published" }
}
401 — Missing API key
{
  "success": false,
  "message": "missing X-API-Key header",
  "code": "UNAUTHORIZED",
  "traceId": "req_a1b2c3d4"
}
403 — Key has no access to this content type
{
  "success": false,
  "message": "Access to this content type is not allowed for this API key",
  "code": "FORBIDDEN",
  "traceId": "req_e5f6g7h8"
}
404 — Entry not found
{
  "success": false,
  "message": "entry not found",
  "code": "NOT_FOUND",
  "traceId": "req_i9j0k1l2"
}

Management API Errors

401 — Wrong key class (delivery key on management endpoint)
{
  "success": false,
  "message": "this endpoint requires a management API key",
  "code": "UNAUTHORIZED",
  "traceId": "req_m1n2o3p4"
}
403 — Missing management scope
{
  "success": false,
  "message": "this key does not have the 'content:publish' scope",
  "code": "FORBIDDEN",
  "traceId": "req_q5r6s7t8"
}
400 — Validation error
{
  "success": false,
  "message": "validation failed",
  "code": "VALIDATION_ERROR",
  "errors": [
    { "field": "slug", "message": "slug is required" },
    { "field": "data.title", "message": "must be a string" }
  ],
  "traceId": "req_u9v0w1x2"
}

Handling Tips

  • Check success first — don't parse data before confirming the request succeeded.
  • On 401 — verify the X-API-Key header is present and correct. For management endpoints, ensure you're using an atlas_mgmt_ key (not atlas_live_).
  • On 403 — the key exists but lacks the required scope. Check the key's scopes in the dashboard (Settings → API Keys). Management keys need content:write, content:publish, or media:write.
  • On 400 with errors array — validation failed. Check err.errors for field-level details.
  • On 429 — respect the rate limit with an exponential-backoff retry strategy. The SDK handles this automatically.
  • Log the traceId from error responses to speed up debugging and support requests.

SDK Error Handling

The TypeScript SDK (@latellu/atlas-sdk) wraps these errors in a typed AtlasError class with full TypeScript support.

Delivery client

Delivery error handling
import { createClient, AtlasError } from '@latellu/atlas-sdk';

const atlas = createClient({ url: '...', apiKey: 'atlas_live_xxx' });

// get() returns null for 404 — no exception
const entry = await atlas.entries('article').get('nonexistent');
if (entry === null) {
  console.log('Not found — handle gracefully');
}

// list() throws on failure
try {
  await atlas.entries('article').list();
} catch (err) {
  if (err instanceof AtlasError) {
    console.error(err.status);  // 401, 403, 429, 500, etc.
    console.error(err.code);    // "UNAUTHORIZED", "FORBIDDEN", etc.
    console.error(err.message); // Human-readable description
  }
}

Management client (Promise)

Management error handling (Promise)
import { createManagementClient, AtlasError } from '@latellu/atlas-sdk/management';

const client = createManagementClient({ url: '...', token: 'atlas_mgmt_xxx' });

try {
  await client.entries('article').create({ slug: '', data: {} });
} catch (err) {
  if (err instanceof AtlasError) {
    console.error(err.status);  // 400, 401, 403, etc.
    console.error(err.code);    // "VALIDATION_ERROR", etc.
    console.error(err.message); // "validation failed"
    console.error(err.errors);  // [{ field: "slug", message: "slug is required" }]
  }
}

Management client (Effect)

Management error handling (Effect)
import { makeManagementClient, AtlasError } from '@latellu/atlas-sdk/management/effect';
import { Effect, Console } from 'effect';

const client = makeManagementClient({ url: '...', token: 'atlas_mgmt_xxx' });

const program = client.entries('article').create({ slug: '', data: {} }).pipe(
  Effect.catchTag('AtlasError', (err) => {
    if (err.status === 400 && err.errors) {
      return Console.error('Validation failed:', err.errors);
    }
    return Console.error(`Failed: ${err.status} ${err.message}`);
  }),
);

await Effect.runPromise(program);

AtlasError properties

PropertyTypeDescription
messagestringHuman-readable error description.
statusnumber | undefinedHTTP status code. Absent for network errors.
codestring | undefinedMachine-readable code (e.g. UNAUTHORIZED, FORBIDDEN, VALIDATION_ERROR).
errors{ field: string; message: string }[] | undefinedValidation errors (management client only).

ManagementConfigError

Thrown immediately (before any request) when the management client is misconfigured:

import { createManagementClient, ManagementConfigError } from '@latellu/atlas-sdk/management';

try {
  // Wrong key prefix — throws immediately
  createManagementClient({ url: '...', token: 'atlas_live_xxx' });
} catch (err) {
  if (err instanceof ManagementConfigError) {
    console.error(err.message); // "management client requires an atlas_mgmt_ token"
  }
}

See SDK Documentation for complete examples with both Promise and Effect surfaces, including retry policies and parallel operations.

On this page