This document defines all error codes used in the Access Layer API and provides guidance for when to add new codes.
Error codes are machine-readable identifiers that allow clients to programmatically handle specific error conditions. They are returned in all error responses under the code field:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid query parameters"
}
}Error codes are defined in src/constants/error.constants.ts and should be treated as stable, public contracts. Changing or removing codes is a breaking change for API consumers.
HTTP Status: 400 Bad Request
Meaning: The request contains invalid data that failed schema validation.
When to use:
- Query parameters fail Zod schema validation
- Request body fails schema validation
- Required fields are missing
- Field values are outside allowed ranges or formats
Example:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid query parameters",
"details": [{ "field": "limit", "message": "Must be between 1 and 100" }]
}
}HTTP Status: 404 Not Found
Meaning: The requested resource does not exist.
When to use:
- A creator profile with the given ID does not exist
- A route path does not exist
- A resource was deleted or never existed
Example:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Creator not found"
}
}HTTP Status: 401 Unauthorized
Meaning: Authentication is required or has failed.
When to use:
- No authentication token is provided when required
- Authentication token is invalid or expired
- Wallet address is required but not provided
- Wallet address is not registered
Example:
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired token"
}
}HTTP Status: 403 Forbidden
Meaning: The authenticated user does not have permission to access this resource.
When to use:
- User is authenticated but lacks required permissions
- Wallet does not own the requested resource
- Access control check fails
Example:
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Wallet does not own the requested resource"
}
}HTTP Status: 409 Conflict
Meaning: The request conflicts with the current state of the resource.
When to use:
- Attempting to create a resource that already exists (unique constraint violation)
- Attempting to update a resource that has been modified since retrieval
- State transition is invalid
Example:
{
"success": false,
"error": {
"code": "CONFLICT",
"message": "Creator handle already exists"
}
}HTTP Status: 400 Bad Request
Meaning: The request is malformed or contains invalid data that cannot be processed.
When to use:
- Request body is not valid JSON
- Request payload exceeds size limits
- Required path parameters are missing
- Query parameters are malformed (but not validation errors)
Example:
{
"success": false,
"error": {
"code": "BAD_REQUEST",
"message": "Request payload too large"
}
}HTTP Status: 500 Internal Server Error
Meaning: An unexpected error occurred on the server.
When to use:
- Unhandled exceptions
- Database connection failures
- External service failures
- Timeout errors
- Any error that cannot be categorized as a client error
Example:
{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error"
}
}HTTP Status: 429 Too Many Requests
Meaning: The client has exceeded the rate limit for this endpoint.
When to use:
- Client has made too many requests in a time window
- Rate limiting middleware has rejected the request
Example:
{
"success": false,
"error": {
"code": "RATE_LIMIT",
"message": "Too many requests. Please try again later."
}
}HTTP Status: 400 Bad Request
Meaning: A database operation failed.
When to use:
- Prisma errors (P2002, P2025, P2003, etc.)
- Database constraint violations
- Foreign key violations
- Record not found in database
Example:
{
"success": false,
"error": {
"code": "DATABASE_ERROR",
"message": "Record already exists (unique constraint violation)"
}
}HTTP Status: 401 Unauthorized
Meaning: JWT token validation failed.
When to use:
- JWT token is invalid or malformed
- JWT token has expired
- JWT signature verification failed
Example:
{
"success": false,
"error": {
"code": "TOKEN_ERROR",
"message": "Token has expired"
}
}Add a new error code only when:
- No existing code fits the error condition. Review the registry above to ensure an existing code cannot be reused.
- The error is a distinct, recoverable client condition. Transient server errors should use
INTERNAL_ERROR. - Clients need to handle this error differently. If clients would handle it the same way as an existing code, reuse the existing code.
- The error is stable and will not change. Error codes are part of the public API contract.
Do not add a new code if:
- The error is a variant of an existing code (e.g., "CREATOR_NOT_FOUND" vs "NOT_FOUND"). Use the existing code with a descriptive message instead.
- The error is transient or internal (e.g., "CACHE_MISS", "RETRY_NEEDED"). Use
INTERNAL_ERROR. - The error is specific to a single endpoint or feature. Use an existing code and vary the message.
- The error is a database-specific error. Use
DATABASE_ERRORand include details in the message.
-
Add the constant to
src/constants/error.constants.ts:export const ErrorCode = { // ... existing codes NEW_ERROR_CODE: 'NEW_ERROR_CODE', } as const;
-
Document the code in this registry with:
- HTTP status code
- Clear meaning
- When to use (with examples)
- Example error response
-
Update error handling in relevant middleware or handlers to use the new code.
-
Add tests that verify the new code is returned in the appropriate error conditions.
-
Update this document with the new code entry.
Scenario: You need a distinct error code for when a creator's profile is incomplete and cannot be published.
Decision: This is a client error (incomplete data), distinct from validation errors (schema violations), and clients need to handle it differently (prompt user to complete profile vs. show validation errors). Add a new code.
Implementation:
-
Add to
error.constants.ts:export const ErrorCode = { // ... existing codes INCOMPLETE_PROFILE: 'INCOMPLETE_PROFILE', } as const;
-
Document in this registry:
### INCOMPLETE_PROFILE **HTTP Status:** 400 Bad Request **Meaning:** The creator profile is missing required fields and cannot be published. **When to use:** - Attempting to publish a profile with missing required fields - Profile lacks required information (bio, avatar, etc.)
-
Use in handler:
if (!profile.bio || !profile.avatarUrl) { return sendError( res, 400, ErrorCode.INCOMPLETE_PROFILE, 'Profile is incomplete' ); }
-
Add test:
it('returns INCOMPLETE_PROFILE when bio is missing', async () => { const res = await publishProfile({ avatarUrl: 'url' }); expect(res.body.error.code).toBe(ErrorCode.INCOMPLETE_PROFILE); });
Error codes are part of the public API contract and should be treated as stable:
- Do not rename existing codes. If a code needs to be renamed, create a new code and deprecate the old one.
- Do not remove codes. If a code is no longer used, mark it as deprecated in comments but keep it defined.
- Do not change HTTP status codes for existing codes. If the status code needs to change, create a new code.
- Do not change meanings of existing codes. If the meaning needs to change, create a new code.
- API Error Handling - Error handling architecture
- Error Constants - Error code definitions
- API Response Utilities - Helper functions for sending errors
- Rate Limiting - Rate limiting configuration and thresholds