Skip to main content
The PlaneConnection API returns consistent JSON error responses for all error types. Every error response includes a human-readable message, a machine-readable code, and a request ID for tracing.

Error Response Format

{
  "error": "Human-readable error message",
  "code": "MACHINE_READABLE_CODE",
  "details": {},
  "requestId": "req_a1b2c3d4"
}
FieldTypeAlways PresentDescription
errorstringYesHuman-readable error description
codestringYesMachine-readable error code (see table below)
detailsobjectNoAdditional context (validation errors, etc.)
requestIdstringYesUnique request ID for support/debugging
Always include the requestId when contacting support about an API error. It enables fast lookup in the request logs.

HTTP Status Codes

StatusCodeDescription
400BAD_REQUESTInvalid request body, missing required fields, or malformed JSON
401UNAUTHORIZEDMissing or invalid authentication credentials
403FORBIDDENAuthenticated but insufficient permissions for this action
404NOT_FOUNDResource does not exist or is not accessible in your workspace
405METHOD_NOT_ALLOWEDHTTP method not supported for this endpoint
409CONFLICTResource conflict (e.g., duplicate entry)
422UNPROCESSABLE_ENTITYRequest is syntactically valid but semantically incorrect
429TOO_MANY_REQUESTSRate limit exceeded — wait and retry
500INTERNAL_SERVER_ERRORUnexpected server error — contact support if persistent
502BAD_GATEWAYUpstream service unavailable
503SERVICE_UNAVAILABLEService temporarily unavailable — retry with exponential backoff
504GATEWAY_TIMEOUTUpstream service timeout

Validation Errors

When a request fails validation (status 400), the error field contains the validation details as a JSON string. The structure follows Zod’s flatten() format:
{
  "error": "{\"fieldErrors\":{\"severity\":[\"Expected number, received string\"],\"likelihood\":[\"Required\"]},\"formErrors\":[]}",
  "code": "BAD_REQUEST",
  "requestId": "req_a1b2c3d4"
}
Parse the error field to extract per-field validation messages:
const response = await fetch("/api/v1/safety/risk-assessments", {
  method: "POST",
  body: JSON.stringify(data),
});

if (!response.ok) {
  const result = await response.json();
  if (result.code === "BAD_REQUEST") {
    try {
      const validation = JSON.parse(result.error);
      // validation.fieldErrors contains per-field errors
      // validation.formErrors contains form-level errors
    } catch {
      // Non-validation error
    }
  }
}

Common Error Scenarios

401 — Missing token
{
  "error": "Authentication required",
  "code": "UNAUTHORIZED",
  "requestId": "req_a1b2c3d4"
}
Fix: Include a valid Authorization: Bearer <token> header or X-API-Key header.401 — Expired token
{
  "error": "Token expired",
  "code": "UNAUTHORIZED",
  "requestId": "req_a1b2c3d4"
}
Fix: Refresh your session token and retry.

Error Handling Best Practices

1
Check the HTTP status code
2
Use the status code to determine the category of error (4xx = client error, 5xx = server error).
3
Parse the error response
4
Extract the code field for programmatic error handling. Use error for user-facing messages.
5
Handle validation errors
6
For 400 responses, parse the error field as JSON to get per-field validation details.
7
Implement retry logic
8
For 429 (rate limited) and 5xx (server errors), implement exponential backoff:
9
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) return response;

    if (response.status === 429 || response.status >= 500) {
      if (attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        await new Promise((r) => setTimeout(r, delay));
        continue;
      }
    }

    throw new Error(`API error: ${response.status}`);
  }
}
10
Log the request ID
11
Always log the requestId from error responses. Include it when contacting support.

Production vs Development

In production, the API returns generic error messages for 500 errors to avoid leaking internal details:
{ "error": "Internal server error", "code": "INTERNAL_SERVER_ERROR" }
In development and staging environments, the actual error message is returned for easier debugging.

Error Tracking

Server errors (5xx) are automatically tracked and reported to the platform’s error monitoring system. Error metrics are collected for operational dashboards.
Last modified on April 11, 2026