Errors
HTTP error responses and status codes returned by the generated API, organized by security layer.
The generated API returns structured error responses with consistent fields across all security layers.
Status Codes
| Code | Meaning | When |
|---|---|---|
200 | OK | Successful GET, PATCH, DELETE |
201 | Created | Successful POST |
207 | Multi-Status | Batch operation with mixed results |
400 | Bad Request | Guard violation, validation error, invalid input |
401 | Unauthorized | Missing or expired authentication |
403 | Forbidden | Access denied (wrong role, condition failed) or firewall blocked it |
404 | Not Found | Record doesn't exist (or firewall blocked with errorMode: 'hide') |
429 | Too Many Requests | Rate limit exceeded |
Error Response Format
All errors use a flat structure with contextual fields:
{
"error": "Insufficient permissions",
"layer": "access",
"code": "ACCESS_ROLE_REQUIRED",
"details": {
"required": ["admin"],
"current": ["member"]
},
"hint": "Contact an administrator to grant necessary permissions"
}| Field | Type | Description |
|---|---|---|
error | string | Human-readable error message |
layer | string | Security layer that rejected the request |
code | string | Machine-readable error code |
details | object | Layer-specific context (optional) |
hint | string | Actionable guidance for resolution (optional) |
Errors by Security Layer
Authentication (401)
Missing or invalid authentication tokens.
{
"error": "Authentication required",
"layer": "authentication",
"code": "AUTH_MISSING",
"hint": "Include Authorization header with Bearer token"
}Error codes:
| Code | Description |
|---|---|
AUTH_MISSING | No Authorization header provided |
AUTH_INVALID_TOKEN | Token is malformed or invalid |
AUTH_EXPIRED | Token has expired |
AUTH_RATE_LIMITED | Too many auth attempts |
Firewall (403)
Records outside the user's firewall scope return 403 Forbidden by default with a structured error:
{
"error": "Record not found or not accessible",
"layer": "firewall",
"code": "FIREWALL_NOT_FOUND",
"hint": "Check the record ID and your organization membership"
}Firewall filtering is transparent — the query is scoped by WHERE organizationId = ? so inaccessible records simply don't appear in results.
Error codes:
| Code | Description |
|---|---|
FIREWALL_NOT_FOUND | Record not found behind firewall (wrong org, soft-deleted, or doesn't exist) |
FIREWALL_ORG_ISOLATION | Record belongs to a different organization |
FIREWALL_USER_ISOLATION | Record belongs to another user |
FIREWALL_SOFT_DELETED | Record has been soft deleted |
For security-hardened deployments, set errorMode: 'hide' in your firewall config to return opaque 404 Not Found responses instead. This prevents attackers from distinguishing between "record exists but you can't access it" and "record doesn't exist".
Access (403)
Access violations return 403 Forbidden when the user's role doesn't match the required roles for the operation.
{
"error": "Insufficient permissions",
"layer": "access",
"code": "ACCESS_ROLE_REQUIRED",
"details": {
"required": ["admin"],
"current": ["member"]
},
"hint": "Contact an administrator to grant necessary permissions"
}Error codes:
| Code | Description |
|---|---|
ACCESS_ROLE_REQUIRED | User doesn't have the required role |
ACCESS_CONDITION_FAILED | Record-level access condition not met |
ACCESS_OWNERSHIP_REQUIRED | User must own the record |
ACCESS_NO_ORG | No active organization set |
Guards (400)
Guard violations return 400 Bad Request when the request body contains fields that aren't allowed.
{
"error": "Field cannot be set during creation",
"layer": "guards",
"code": "GUARD_FIELD_NOT_CREATEABLE",
"details": {
"fields": ["status"]
},
"hint": "These fields are set automatically or must be omitted"
}Error codes:
| Code | Description |
|---|---|
GUARD_FIELD_NOT_CREATEABLE | Field not in createable list |
GUARD_FIELD_NOT_UPDATABLE | Field not in updatable list |
GUARD_FIELD_PROTECTED | Field is action-only (protected) |
GUARD_FIELD_IMMUTABLE | Field cannot be modified after creation |
GUARD_SYSTEM_MANAGED | System field (createdAt, modifiedAt, etc.) |
Masking
Masking doesn't produce errors — it silently transforms field values in the response.
Batch Errors
Batch operations can return:
- 201 — All records succeeded
- 207 — Partial success (some records failed)
- 400 — Atomic mode and at least one record failed (all rolled back)
Partial Success (207)
{
"success": [{ "id": "room_1", "name": "Room A" }],
"errors": [
{
"index": 1,
"record": { "name": "Room B", "status": "active" },
"error": {
"error": "Field cannot be set during creation",
"layer": "guards",
"code": "GUARD_FIELD_NOT_CREATEABLE",
"details": { "fields": ["status"] },
"hint": "These fields are set automatically or must be omitted"
}
}
],
"meta": { "total": 2, "succeeded": 1, "failed": 1, "atomic": false }
}Atomic Failure (400)
{
"error": "Batch operation failed in atomic mode",
"layer": "validation",
"code": "BATCH_ATOMIC_FAILED",
"details": {
"failedAt": 2,
"reason": { "error": "Not found", "code": "NOT_FOUND" }
},
"hint": "Transaction rolled back. Fix the error and retry the entire batch."
}Batch error codes:
| Code | Description |
|---|---|
BATCH_SIZE_EXCEEDED | Too many records in a single request |
BATCH_ATOMIC_FAILED | Atomic batch failed, all changes rolled back |
BATCH_MISSING_IDS | Batch update/delete missing required IDs |