---
title: Error Code Catalog
description: Complete reference for all ObjectStack error codes with causes, fixes, and retry strategies
---

# Error Code Catalog

ObjectStack uses a structured error system with **9 error categories** and **41+ standardized error codes**. Every error includes a machine-readable code, HTTP status mapping, and retry guidance.

<Callout type="info">
**Source:** `packages/spec/src/api/errors.zod.ts`  
**Import:** `import { StandardErrorCodeSchema, ErrorCategorySchema, ErrorResponseSchema } from '@objectstack/spec/api'`
</Callout>

---

## Error Categories

| Category | HTTP Status | Description |
|:---|:---:|:---|
| `validation` | 400 | Request data failed validation |
| `authentication` | 401 | Identity not verified |
| `authorization` | 403 | Insufficient permissions |
| `not_found` | 404 | Resource does not exist |
| `conflict` | 409 | State conflict or duplicate |
| `rate_limit` | 429 | Too many requests |
| `server` | 500 | Internal server error |
| `external` | 502 | External service failure |
| `maintenance` | 503 | System under maintenance |

---

## Retry Strategies

| Strategy | Description | When to Use |
|:---|:---|:---|
| `no_retry` | Do not retry the request | Validation errors, permission denied |
| `retry_immediate` | Retry immediately | Transient network errors |
| `retry_backoff` | Retry with exponential backoff | Rate limits, server errors |
| `retry_after` | Wait the specified `retryAfter` seconds | Rate limit with explicit cooldown |

---

## Validation Errors (400)

### `validation_error`
**Cause:** Generic validation failure — request body does not match expected schema.  
**Fix:** Check the `fieldErrors` array for specific field-level issues.  
**Retry:** `no_retry`

```json
{
  "code": "validation_error",
  "message": "Request validation failed",
  "category": "validation",
  "httpStatus": 400,
  "retryable": false,
  "fieldErrors": [
    { "field": "email", "message": "Invalid email format", "code": "invalid_format" }
  ]
}
```

### `invalid_field`
**Cause:** A field name in the request does not exist on the target object.  
**Fix:** Check the object schema for valid field names. Use `objectstack explain <object>` to see available fields.  
**Retry:** `no_retry`

### `missing_required_field`
**Cause:** A required field was not provided in the request body.  
**Fix:** Include the missing field. Check `fieldErrors` for the field name.  
**Retry:** `no_retry`

### `invalid_format`
**Cause:** Field value does not match the expected format (e.g., invalid email, wrong date format).  
**Fix:** Ensure the value matches the field's `format` constraint or built-in type validation.  
**Retry:** `no_retry`

### `value_too_long`
**Cause:** String value exceeds the field's `maxLength` constraint.  
**Fix:** Truncate the value to the maximum allowed length.  
**Retry:** `no_retry`

### `value_too_short`
**Cause:** String value is below the field's `minLength` constraint.  
**Fix:** Provide a longer value that meets the minimum length requirement.  
**Retry:** `no_retry`

### `value_out_of_range`
**Cause:** Numeric value is outside the field's `min`/`max` range.  
**Fix:** Ensure the value is within the allowed range.  
**Retry:** `no_retry`

### `invalid_reference`
**Cause:** A `lookup` or `master_detail` field references a record that does not exist.  
**Fix:** Verify the referenced record ID exists in the target object.  
**Retry:** `no_retry`

### `duplicate_value`
**Cause:** A field with `unique: true` already has a record with the same value.  
**Fix:** Use a different value or update the existing record.  
**Retry:** `no_retry`

### `invalid_query`
**Cause:** The query structure is malformed.  
**Fix:** Check the query syntax against the [Query Cheat Sheet](/docs/guides/cheatsheets/query-cheat-sheet).  
**Retry:** `no_retry`

### `invalid_filter`
**Cause:** A filter operator or field in the `where` clause is invalid.  
**Fix:** Use valid filter operators (`$eq`, `$ne`, `$gt`, `$lt`, `$in`, `$contains`, etc.).  
**Retry:** `no_retry`

### `invalid_sort`
**Cause:** The `orderBy` clause references a non-existent or non-sortable field.  
**Fix:** Ensure the field exists and has `sortable: true`.  
**Retry:** `no_retry`

### `max_records_exceeded`
**Cause:** The request attempts to create or return more records than the system limit.  
**Fix:** Use pagination (`limit`/`offset` or cursor-based) for large datasets. Batch operations for bulk creates.  
**Retry:** `no_retry`

---

## Authentication Errors (401)

### `unauthenticated`
**Cause:** No authentication credentials were provided.  
**Fix:** Include a valid `Authorization` header (Bearer token, API key, or session cookie).  
**Retry:** `no_retry`

### `invalid_credentials`
**Cause:** Username/password combination is incorrect.  
**Fix:** Verify credentials and try again. After multiple failures, account may be locked.  
**Retry:** `no_retry`

### `expired_token`
**Cause:** The authentication token (JWT, session token) has expired.  
**Fix:** Obtain a new token using the refresh token endpoint or re-authenticate.  
**Retry:** `retry_immediate` (after refreshing token)

### `invalid_token`
**Cause:** The authentication token is malformed or has been tampered with.  
**Fix:** Obtain a fresh token from the authentication endpoint.  
**Retry:** `no_retry`

### `session_expired`
**Cause:** The user session has timed out due to inactivity.  
**Fix:** Re-authenticate to start a new session.  
**Retry:** `no_retry`

### `mfa_required`
**Cause:** Multi-factor authentication is required but the MFA challenge has not been completed.  
**Fix:** Complete the MFA verification step before proceeding.  
**Retry:** `no_retry`

### `email_not_verified`
**Cause:** The user's email address has not been verified.  
**Fix:** Complete email verification through the link sent to the user's email.  
**Retry:** `no_retry`

---

## Authorization Errors (403)

### `permission_denied`
**Cause:** The authenticated user does not have permission for this operation.  
**Fix:** Request the necessary permissions from an administrator, or use an account with the required role.  
**Retry:** `no_retry`

### `insufficient_privileges`
**Cause:** The user has some access but lacks the specific privilege required for this action.  
**Fix:** Contact an administrator to grant the necessary privilege.  
**Retry:** `no_retry`

### `field_not_accessible`
**Cause:** The user does not have access to a specific field on the object.  
**Fix:** Remove the inaccessible field from the request, or request field-level access.  
**Retry:** `no_retry`

### `record_not_accessible`
**Cause:** The user cannot access this specific record due to record-level sharing rules.  
**Fix:** Request access to the record from its owner or an administrator.  
**Retry:** `no_retry`

### `license_required`
**Cause:** The feature requires a specific license that is not active.  
**Fix:** Upgrade the license or contact your administrator.  
**Retry:** `no_retry`

### `ip_restricted`
**Cause:** The request originates from an IP address that is not in the allowlist.  
**Fix:** Ensure the request comes from an approved IP range, or update the IP restriction settings.  
**Retry:** `no_retry`

### `time_restricted`
**Cause:** Access is limited to specific time windows and the current time is outside the allowed range.  
**Fix:** Retry during the allowed time window.  
**Retry:** `retry_after`

---

## Not Found Errors (404)

### `resource_not_found`
**Cause:** The requested resource does not exist (generic).  
**Fix:** Verify the resource identifier and endpoint path.  
**Retry:** `no_retry`

### `object_not_found`
**Cause:** The specified object (table/entity) does not exist in the schema.  
**Fix:** Check the object name. Use `objectstack explain` to list available objects.  
**Retry:** `no_retry`

### `record_not_found`
**Cause:** No record exists with the given ID in the specified object.  
**Fix:** Verify the record ID. The record may have been deleted.  
**Retry:** `no_retry`

### `field_not_found`
**Cause:** The specified field does not exist on the object.  
**Fix:** Check the field name against the object schema. Field names are snake_case.  
**Retry:** `no_retry`

### `endpoint_not_found`
**Cause:** The API endpoint path does not match any registered route.  
**Fix:** Verify the URL path and HTTP method. Check the API discovery endpoint for available routes.  
**Retry:** `no_retry`

---

## Conflict Errors (409)

### `resource_conflict`
**Cause:** The operation conflicts with the current state of the resource.  
**Fix:** Fetch the latest resource state and retry the operation.  
**Retry:** `retry_immediate`

### `concurrent_modification`
**Cause:** The record was modified by another user/process since you last read it (optimistic locking failure).  
**Fix:** Re-fetch the record, merge changes, and retry.  
**Retry:** `retry_immediate`

### `delete_restricted`
**Cause:** The record cannot be deleted because other records depend on it (referential integrity).  
**Fix:** Delete or reassign dependent records first, then retry the delete.  
**Retry:** `no_retry`

### `duplicate_record`
**Cause:** A record with the same unique key already exists.  
**Fix:** Update the existing record instead, or use a different unique key value.  
**Retry:** `no_retry`

### `lock_conflict`
**Cause:** The record is locked by another process or user.  
**Fix:** Wait for the lock to be released, or contact the lock holder.  
**Retry:** `retry_backoff`

---

## Rate Limit Errors (429)

### `rate_limit_exceeded`
**Cause:** Too many requests in the current time window.  
**Fix:** Reduce request frequency. Check the `retryAfter` field for the wait time.  
**Retry:** `retry_after`

### `quota_exceeded`
**Cause:** The API usage quota for the current period has been exhausted.  
**Fix:** Wait for the quota to reset (check `retryAfter`), or upgrade the plan.  
**Retry:** `retry_after`

### `concurrent_limit_exceeded`
**Cause:** Too many concurrent requests from the same client.  
**Fix:** Reduce parallel request count. Implement request queuing.  
**Retry:** `retry_backoff`

---

## Server Errors (500)

### `internal_error`
**Cause:** An unexpected server-side error occurred.  
**Fix:** Report the issue with the `requestId` and `traceId`. Retry may succeed.  
**Retry:** `retry_backoff`

### `database_error`
**Cause:** A database operation failed (connection, query, constraint).  
**Fix:** Report the issue. May be transient — retry with backoff.  
**Retry:** `retry_backoff`

### `timeout`
**Cause:** The operation exceeded the maximum allowed time.  
**Fix:** Simplify the query/operation. For large datasets, use pagination or async processing.  
**Retry:** `retry_backoff`

### `service_unavailable`
**Cause:** A required internal service is temporarily unavailable.  
**Fix:** Retry after a brief delay. Check system status.  
**Retry:** `retry_backoff`

### `not_implemented`
**Cause:** The requested feature or endpoint is not yet implemented.  
**Fix:** Check the documentation for alternative approaches, or wait for the feature release.  
**Retry:** `no_retry`

---

## External Service Errors (502)

### `external_service_error`
**Cause:** An external API or service returned an error.  
**Fix:** Check the external service status. The `details` field may contain the upstream error.  
**Retry:** `retry_backoff`

### `integration_error`
**Cause:** An integration connector encountered an error.  
**Fix:** Verify the integration configuration and credentials.  
**Retry:** `retry_backoff`

### `webhook_delivery_failed`
**Cause:** A webhook delivery attempt failed (target unreachable or returned error).  
**Fix:** Verify the webhook URL is accessible. The system will auto-retry per delivery policy.  
**Retry:** `retry_backoff`

---

## Batch Operation Errors

### `batch_partial_failure`
**Cause:** Some operations in a batch request succeeded while others failed.  
**Fix:** Check the `details` for individual operation results. Retry only the failed operations.  
**Retry:** `retry_immediate` (failed operations only)

### `batch_complete_failure`
**Cause:** All operations in the batch request failed.  
**Fix:** Check the `details` for root cause. Fix and retry the entire batch.  
**Retry:** `retry_backoff`

### `transaction_failed`
**Cause:** A database transaction failed and was rolled back.  
**Fix:** Check the `details` for the specific failure. Retry the entire transaction.  
**Retry:** `retry_backoff`

---

## Error Response Structure

Every error response follows the `EnhancedApiError` schema:

```typescript
interface EnhancedApiError {
  code: StandardErrorCode;       // Machine-readable error code
  message: string;               // Human-readable description
  category?: ErrorCategory;      // Error category
  httpStatus?: number;           // HTTP status code
  retryable: boolean;            // Whether retry may succeed
  retryStrategy?: RetryStrategy; // Recommended retry approach
  retryAfter?: number;           // Seconds to wait (for rate limits)
  details?: unknown;             // Additional error context
  fieldErrors?: FieldError[];    // Field-specific validation errors
  timestamp?: string;            // ISO 8601 timestamp
  requestId?: string;            // Request tracking ID
  traceId?: string;              // Distributed trace ID
  documentation?: string;        // URL to error documentation
  helpText?: string;             // Suggested resolution actions
}
```

### Field Error Structure

```typescript
interface FieldError {
  field: string;    // Field name that has the error
  message: string;  // Human-readable error for this field
  code?: string;    // Field-level error code
  value?: unknown;  // The invalid value (if safe to include)
}
```

---

## Client-Side Error Handling

### TypeScript Example

```typescript
import type { EnhancedApiError } from '@objectstack/spec/api';

async function handleApiCall() {
  try {
    const result = await client.records.create('task', { title: 'New Task' });
    return result;
  } catch (error) {
    const apiError = error as EnhancedApiError;

    switch (apiError.category) {
      case 'validation':
        // Show field-level errors to the user
        apiError.fieldErrors?.forEach(fe => {
          showFieldError(fe.field, fe.message);
        });
        break;

      case 'authentication':
        // Redirect to login
        if (apiError.code === 'expired_token') {
          await refreshToken();
          return handleApiCall(); // Retry
        }
        redirectToLogin();
        break;

      case 'rate_limit':
        // Wait and retry
        const waitTime = apiError.retryAfter ?? 60;
        await sleep(waitTime * 1000);
        return handleApiCall();

      case 'server':
      case 'external':
        // Log and retry with backoff
        console.error(`Server error [${apiError.requestId}]:`, apiError.message);
        break;

      default:
        showGenericError(apiError.message);
    }
  }
}
```

---

## HTTP Status Quick Reference

| Status | Category | Common Codes |
|:---:|:---|:---|
| 400 | `validation` | `validation_error`, `invalid_field`, `missing_required_field`, `invalid_query` |
| 401 | `authentication` | `unauthenticated`, `expired_token`, `invalid_credentials` |
| 403 | `authorization` | `permission_denied`, `field_not_accessible`, `license_required` |
| 404 | `not_found` | `record_not_found`, `object_not_found`, `endpoint_not_found` |
| 409 | `conflict` | `concurrent_modification`, `duplicate_record`, `delete_restricted` |
| 429 | `rate_limit` | `rate_limit_exceeded`, `quota_exceeded` |
| 500 | `server` | `internal_error`, `database_error`, `timeout` |
| 502 | `external` | `external_service_error`, `integration_error` |
| 503 | `maintenance` | `service_unavailable` |
