title
Errors schema — API Protocol reference
navTitle
Errors
description
Provides consistent, machine-readable error codes across the platform.
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
Standardized Error Codes Protocol
Implements P0 requirement for ObjectStack kernel.
Provides consistent, machine-readable error codes across the platform.
Features:
Categorized error codes (validation, authentication, authorization, etc.)
HTTP status code mapping
Localization support
Retry guidance
Industry alignment: Google Cloud Errors, AWS Error Codes, Stripe API Errors
**Source:** `packages/spec/src/api/errors.zod.ts`
import { EnhancedApiErrorSchema , ErrorCategory , ErrorResponseSchema , FieldErrorSchema , FieldErrorCode , RetryStrategy , StandardErrorCode } from '@objectstack/spec/api' ;
import type { EnhancedApiError , ErrorCategory , ErrorResponse , FieldError , FieldErrorCode , RetryStrategy , StandardErrorCode } from '@objectstack/spec/api' ;
// Validate data
const result = EnhancedApiErrorSchema . parse ( data ) ;
Property
Type
Required
Description
code
Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | 'INVALID_FORMAT' | 'VALUE_TOO_LONG' | 'VALUE_TOO_SHORT' | 'VALUE_OUT_OF_RANGE' | … +42 more>
✅
Machine-readable error code
message
string
✅
Human-readable error message
userMessage
string
optional
Producer-marked user-facing refusal text, verbatim — see ApiErrorSchema.userMessage. Present only when the producer opted in at throw time; unmarked errors keep the generic consumer substitution.
refusal
true
optional
Producer-declared deliberate refusal — see ApiErrorSchema.refusal. Present only when the producer declared it at throw time; a declared 5xx without it is a fault whose message is withheld. Until the withhold arms read the declaration, a declared refusal is still withheld.
category
Enum<'validation' | 'authentication' | 'authorization' | 'not_found' | 'conflict' | 'rate_limit' | 'server' | 'external' | 'maintenance'>
optional
Error category
httpStatus
number
optional
HTTP status code
retryable
boolean
optional (default: false)
Whether the request can be retried
retryStrategy
Enum<'no_retry' | 'retry_immediate' | 'retry_backoff' | 'retry_after'>
optional
Recommended retry strategy
retryAfterSeconds
number
optional
Seconds to wait before retrying
retryAfter
never
optional
[REMOVED] EnhancedApiError.retryAfter was renamed to retryAfterSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to retryAfterSeconds; the value (seconds) is unchanged. This is the ADR-0112 error envelope, not the HTTP Retry-After response header — that header keeps its RFC 9110 name and is untouched.
details
any
optional
Additional error context
fields
{ field: string; code: Enum<'required' | 'invalid_type' | 'invalid_shape' | 'unknown_field' | …>; message: string; label?: string; … }[]
optional
One entry per offending value
fieldErrors
never
optional
[REMOVED] EnhancedApiError.fieldErrors was renamed to fields in @objectstack/spec 17 (ADR-0114 D4) — the array is unchanged, only the property name. Every producer already emitted fields; fieldErrors was declared and never emitted, so a reader keying on it was reading a field no server sent.
timestamp
string
optional
When the error occurred
requestId
string
optional
Request ID for tracking
traceId
string
optional
Distributed trace ID
documentation
string
optional
URL to error documentation
helpText
string
optional
Suggested actions to resolve the error
Allowed Values: EnhancedApiError.code
VALIDATION_ERROR
INVALID_FIELD
MISSING_REQUIRED_FIELD
INVALID_FORMAT
VALUE_TOO_LONG
VALUE_TOO_SHORT
VALUE_OUT_OF_RANGE
INVALID_REFERENCE
DUPLICATE_VALUE
INVALID_QUERY
INVALID_FILTER
INVALID_SORT
MAX_RECORDS_EXCEEDED
UNAUTHENTICATED
INVALID_CREDENTIALS
EXPIRED_TOKEN
INVALID_TOKEN
SESSION_EXPIRED
MFA_REQUIRED
EMAIL_NOT_VERIFIED
PERMISSION_DENIED
INSUFFICIENT_PRIVILEGES
FIELD_NOT_ACCESSIBLE
RECORD_NOT_ACCESSIBLE
LICENSE_REQUIRED
IP_RESTRICTED
TIME_RESTRICTED
RESOURCE_NOT_FOUND
OBJECT_NOT_FOUND
RECORD_NOT_FOUND
FIELD_NOT_FOUND
ENDPOINT_NOT_FOUND
RESOURCE_CONFLICT
CONCURRENT_MODIFICATION
DELETE_RESTRICTED
DUPLICATE_RECORD
LOCK_CONFLICT
METHOD_NOT_ALLOWED
PRECONDITION_REQUIRED
RATE_LIMIT_EXCEEDED
QUOTA_EXCEEDED
INTERNAL_ERROR
DATABASE_ERROR
TIMEOUT
SERVICE_UNAVAILABLE
NOT_IMPLEMENTED
EXTERNAL_SERVICE_ERROR
INTEGRATION_ERROR
WEBHOOK_DELIVERY_FAILED
Nested Shape: EnhancedApiError.fields[number]
Property
Type
Required
Description
field
string
✅
Field path (supports dot notation)
code
Enum<'required' | 'invalid_type' | 'invalid_shape' | 'unknown_field' | …>
✅
Which constraint the value violated (field-level catalog, ADR-0114)
message
string
✅
Human-readable error message, rendered in the caller’s locale
label
string
optional
Field display label in the caller’s locale
value
any
optional
The invalid value that was provided
constraint
Record<string, any>
optional
The constraint that was violated, as discrete values (e.g. { maxLength: 512, actual: 3000 })
validation
authentication
authorization
not_found
conflict
rate_limit
server
external
maintenance
Property
Type
Required
Description
success
false
✅
Always false for error responses
error
{ code: Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>; message: string; userMessage?: string; refusal?: true; … }
✅
Error details
meta
{ timestamp?: string; requestId?: string; traceId?: string }
optional
Response metadata
Nested Shape: ErrorResponse.error
Property
Type
Required
Description
code
Enum<'VALIDATION_ERROR' | 'INVALID_FIELD' | 'MISSING_REQUIRED_FIELD' | …>
✅
Machine-readable error code
message
string
✅
Human-readable error message
userMessage
string
optional
Producer-marked user-facing refusal text, verbatim — see ApiErrorSchema.userMessage. Present only when the producer opted in at throw time; unmarked errors keep the generic consumer substitution.
refusal
true
optional
Producer-declared deliberate refusal — see ApiErrorSchema.refusal. Present only when the producer declared it at throw time; a declared 5xx without it is a fault whose message is withheld. Until the withhold arms read the declaration, a declared refusal is still withheld.
category
Enum<'validation' | 'authentication' | 'authorization' | 'not_found' | 'conflict' | …>
optional
Error category
httpStatus
number
optional
HTTP status code
retryable
boolean
optional (default: false)
Whether the request can be retried
retryStrategy
Enum<'no_retry' | 'retry_immediate' | 'retry_backoff' | 'retry_after'>
optional
Recommended retry strategy
retryAfterSeconds
number
optional
Seconds to wait before retrying
retryAfter
never
optional
[REMOVED] EnhancedApiError.retryAfter was renamed to retryAfterSeconds in @objectstack/spec 17 — the unit of a duration-shaped number lives in the key name, not only in the describe prose. Rename the key to retryAfterSeconds; the value (seconds) is unchanged. This is the ADR-0112 error envelope, not the HTTP Retry-After response header — that header keeps its RFC 9110 name and is untouched.
details
any
optional
Additional error context
fields
{ field: string; code: Enum<'required' | 'invalid_type' | 'invalid_shape' | 'unknown_field' | …>; message: string; label?: string; … }[]
optional
One entry per offending value
fieldErrors
never
optional
[REMOVED] EnhancedApiError.fieldErrors was renamed to fields in @objectstack/spec 17 (ADR-0114 D4) — the array is unchanged, only the property name. Every producer already emitted fields; fieldErrors was declared and never emitted, so a reader keying on it was reading a field no server sent.
timestamp
string
optional
When the error occurred
requestId
string
optional
Request ID for tracking
traceId
string
optional
Distributed trace ID
documentation
string
optional
URL to error documentation
helpText
string
optional
Suggested actions to resolve the error
Property
Type
Required
Description
field
string
✅
Field path (supports dot notation)
code
Enum<'required' | 'invalid_type' | 'invalid_shape' | 'unknown_field' | 'invalid_boolean' | 'invalid_number' | 'invalid_date' | 'invalid_time' | 'invalid_email' | … +22 more>
✅
Which constraint the value violated (field-level catalog, ADR-0114)
message
string
✅
Human-readable error message, rendered in the caller’s locale
label
string
optional
Field display label in the caller’s locale
value
any
optional
The invalid value that was provided
constraint
Record<string, any>
optional
The constraint that was violated, as discrete values (e.g. { maxLength: 512, actual: 3000 })
Allowed Values: FieldError.code
required
invalid_type
invalid_shape
unknown_field
invalid_boolean
invalid_number
invalid_date
invalid_time
invalid_email
invalid_url
invalid_phone
invalid_json
invalid_format
min_length
max_length
min_value
max_value
max_scale
max_precision
min_items
max_items
invalid_option
value_domain
invalid_value
reference_not_found
reference_ambiguous
reference_user_banned
rule_violation
json_schema_violation
invalid_initial_state
invalid_transition
required
invalid_type
invalid_shape
unknown_field
invalid_boolean
invalid_number
invalid_date
invalid_time
invalid_email
invalid_url
invalid_phone
invalid_json
invalid_format
min_length
max_length
min_value
max_value
max_scale
max_precision
min_items
max_items
invalid_option
value_domain
invalid_value
reference_not_found
reference_ambiguous
reference_user_banned
rule_violation
json_schema_violation
invalid_initial_state
invalid_transition
no_retry
retry_immediate
retry_backoff
retry_after
VALIDATION_ERROR
INVALID_FIELD
MISSING_REQUIRED_FIELD
INVALID_FORMAT
VALUE_TOO_LONG
VALUE_TOO_SHORT
VALUE_OUT_OF_RANGE
INVALID_REFERENCE
DUPLICATE_VALUE
INVALID_QUERY
INVALID_FILTER
INVALID_SORT
MAX_RECORDS_EXCEEDED
UNAUTHENTICATED
INVALID_CREDENTIALS
EXPIRED_TOKEN
INVALID_TOKEN
SESSION_EXPIRED
MFA_REQUIRED
EMAIL_NOT_VERIFIED
PERMISSION_DENIED
INSUFFICIENT_PRIVILEGES
FIELD_NOT_ACCESSIBLE
RECORD_NOT_ACCESSIBLE
LICENSE_REQUIRED
IP_RESTRICTED
TIME_RESTRICTED
RESOURCE_NOT_FOUND
OBJECT_NOT_FOUND
RECORD_NOT_FOUND
FIELD_NOT_FOUND
ENDPOINT_NOT_FOUND
RESOURCE_CONFLICT
CONCURRENT_MODIFICATION
DELETE_RESTRICTED
DUPLICATE_RECORD
LOCK_CONFLICT
METHOD_NOT_ALLOWED
PRECONDITION_REQUIRED
RATE_LIMIT_EXCEEDED
QUOTA_EXCEEDED
INTERNAL_ERROR
DATABASE_ERROR
TIMEOUT
SERVICE_UNAVAILABLE
NOT_IMPLEMENTED
EXTERNAL_SERVICE_ERROR
INTEGRATION_ERROR
WEBHOOK_DELIVERY_FAILED