> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soundchecklive.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Codes

> API error codes and how to resolve them

Complete reference of API error codes, their meanings, and how to resolve them.

***

## HTTP Status Codes

### Success Codes

| Code | Name | Description |
| - | - | - |
| `200` | OK | Request succeeded |
| `201` | Created | Resource created successfully |
| `204` | No Content | Request succeeded, no content to return |

### Client Error Codes

| Code | Name | Common Causes |
| - | - | - |
| `400` | Bad Request | Invalid input, malformed JSON, validation error |
| `401` | Unauthorized | Missing or invalid authentication token |
| `403` | Forbidden | Valid token but insufficient permissions |
| `404` | Not Found | Resource doesn't exist or not accessible |
| `409` | Conflict | Resource already exists, duplicate entry |
| `422` | Unprocessable Entity | Valid syntax but semantic errors |
| `429` | Too Many Requests | Rate limit exceeded |

### Server Error Codes

| Code | Name | Description |
| - | - | - |
| `500` | Internal Server Error | Unexpected server error |
| `502` | Bad Gateway | Upstream service unavailable |
| `503` | Service Unavailable | Server temporarily unavailable |
| `504` | Gateway Timeout | Upstream service timeout |

***

## API Error Response Format

All API errors follow this standardized flat format:

```json theme={null}
{
  "status": 400,
  "code": "INVALID_REQUEST",
  "message": "Event ID must be a valid UUID",
  "details": "optional additional context"
}
```

**Field meanings:**

* `status`: HTTP status code (always matches response header)
* `code`: Machine-readable error code for client-side branching
* `message`: Human-readable message safe for UI display and developer debugging
* `details`: Additional context (omitted if not needed), never raw error details

***

## Authentication Errors

> [accordion] invalid\_token
>
> **HTTP Status:** 401
>
> **Message:** "Invalid or expired authentication token"
>
> **Causes:**
>
> * Token has expired (default: 1 hour)
> * Token was revoked
> * Token is malformed
>
> **Solutions:**
>
> 1. Refresh the token using Clerk SDK
> 2. Sign out and sign back in
> 3. Check token format is `Bearer <token>`
>
> ```bash theme={null}
> # Verify token is being sent
> curl -v -H "Authorization: Bearer $TOKEN" \
>   http://localhost:4000/api/v1/users/me
> ```

> [accordion] missing\_token
>
> **HTTP Status:** 401
>
> **Message:** "Authentication token required"
>
> **Causes:**
>
> * Authorization header not included
> * Header format incorrect
>
> **Solutions:**
>
> 1. Add `Authorization: Bearer <token>` header
> 2. Ensure token is not empty
> 3. Check for typos in header name
>
> ```javascript theme={null}
> // Correct format
> headers: {
>   'Authorization': `Bearer ${token}`
> }
> ```

> [accordion] token\_expired
>
> **HTTP Status:** 401
>
> **Message:** "Authentication token has expired"
>
> **Causes:**
>
> * JWT token exceeded its lifetime (1 hour default)
>
> **Solutions:**
>
> 1. Call `getToken()` from Clerk to get fresh token
> 2. Clerk SDK handles refresh automatically in most cases
> 3. Check if user session is still valid
>
> ```typescript theme={null}
> // React Native
> const token = await getToken();
> ```

> [accordion] invalid\_signature
>
> **HTTP Status:** 401
>
> **Message:** "Token signature verification failed"
>
> **Causes:**
>
> * Token was modified
> * Wrong Clerk instance (test vs production)
> * Clerk secret key mismatch
>
> **Solutions:**
>
> 1. Verify `CLERK_SECRET_KEY` matches Clerk Dashboard
> 2. Ensure using correct environment (test/prod)
> 3. Check token hasn't been tampered with

***

## Authorization Errors

> [accordion] forbidden
>
> **HTTP Status:** 403
>
> **Message:** "You don't have permission to perform this action"
>
> **Causes:**
>
> * User lacks required role (Owner/Admin)
> * Resource belongs to different organization
> * Feature requires higher subscription tier
>
> **Solutions:**
>
> 1. Check user's role in the organization
> 2. Verify organization membership
> 3. Check subscription tier for feature access
>
> ```bash theme={null}
> # Check user's organizations
> curl -H "Authorization: Bearer $TOKEN" \
>   http://localhost:4000/api/v1/users/me/organizations
> ```

> [accordion] not\_member
>
> **HTTP Status:** 403
>
> **Message:** "User is not a member of this organization"
>
> **Causes:**
>
> * User trying to access organization they don't belong to
> * User was removed from organization
>
> **Solutions:**
>
> 1. Verify user is member of the organization
> 2. Check if membership was revoked
> 3. Request invitation to organization

> [accordion] PLAN\_UPGRADE\_REQUIRED
>
> **HTTP Status:** 403
>
> **Message:** "{Feature} is available on {Tier} and above"
>
> **Causes:**
>
> * The organization's plan is below the tier the feature needs in `entitlements/registry.json`, and that entitlement is `enforced`
>
> The body also carries `entitlement` (the registry key), `required_tier`, and `current_tier`, so a client can name the plan to upgrade to:
>
> ```json theme={null}
> {
>   "status": 403,
>   "code": "PLAN_UPGRADE_REQUIRED",
>   "message": "Finances is available on Pro and above",
>   "entitlement": "finances",
>   "required_tier": "pro",
>   "current_tier": "starter"
> }
> ```
>
> **Solutions:**
>
> 1. Upgrade the plan under **Settings → Billing & payments → Billing**
> 2. Check the org's tier with `GET /api/v1/organizations/{orgId}/entitlements`

> [accordion] insufficient\_role
>
> **HTTP Status:** 403
>
> **Message:** "This action requires Owner or Admin role"
>
> **Causes:**
>
> * User has Member role, needs Admin or Owner
> * Specific action restricted to organization owner
>
> **Solutions:**
>
> 1. Request role upgrade from organization owner
> 2. Use account with appropriate permissions

***

## Validation Errors

> [accordion] validation\_error
>
> **HTTP Status:** 400
>
> **Message:** "Validation failed"
>
> **Response includes details:**
>
> ```json theme={null}
> {
>   "error": {
>     "code": "validation_error",
>     "message": "Validation failed",
>     "details": {
>       "fields": {
>         "email": "Invalid email format",
>         "date": "Date must be in the future"
>       }
>     }
>   }
> }
> ```
>
> **Solutions:**
>
> 1. Check the `details.fields` for specific errors
> 2. Validate input before sending
> 3. Ensure required fields are present

> [accordion] invalid\_json
>
> **HTTP Status:** 400
>
> **Message:** "Invalid JSON in request body"
>
> **Causes:**
>
> * Malformed JSON syntax
> * Missing Content-Type header
> * Empty request body when body expected
>
> **Solutions:**
>
> 1. Validate JSON syntax
> 2. Add `Content-Type: application/json` header
> 3. Ensure body is not empty
>
> ```bash theme={null}
> # Validate JSON
> echo '{"name": "test"}' | python -m json.tool
> ```

> [accordion] missing\_field
>
> **HTTP Status:** 400
>
> **Message:** "Required field missing: {field_name}"
>
> **Causes:**
>
> * Required field not included in request
> * Field name typo (camelCase vs snake\_case)
>
> **Solutions:**
>
> 1. Check API documentation for required fields
> 2. Verify field naming convention (API uses snake\_case)

> [accordion] invalid\_date
>
> **HTTP Status:** 400
>
> **Message:** "Invalid date format"
>
> **Expected format:** ISO 8601 (`2024-06-15T19:00:00Z`)
>
> **Solutions:**
>
> 1. Use ISO 8601 format with timezone
> 2. Ensure date is valid (not Feb 30)
>
> ```javascript theme={null}
> // Correct format
> const date = new Date().toISOString();
> // "2024-06-15T19:00:00.000Z"
> ```

***

## Resource Errors

> [accordion] not\_found
>
> **HTTP Status:** 404
>
> **Message:** "Resource not found"
>
> **Causes:**
>
> * Resource doesn't exist
> * Resource was deleted
> * Wrong ID format
> * No permission to view resource
>
> **Solutions:**
>
> 1. Verify the resource ID is correct
> 2. Check if resource was deleted
> 3. Ensure user has access to the resource
>
> ```bash theme={null}
> # Check if event exists
> curl -H "Authorization: Bearer $TOKEN" \
>   http://localhost:4000/api/v1/events/{event_id}
> ```

> [accordion] already\_exists
>
> **HTTP Status:** 409
>
> **Message:** "Resource already exists"
>
> **Causes:**
>
> * Duplicate email address
> * Duplicate organization slug
> * Duplicate invitation for same user/event
>
> **Solutions:**
>
> 1. Use unique values for unique fields
> 2. Check if resource already exists before creating
> 3. Update existing resource instead

> [accordion] resource\_in\_use
>
> **HTTP Status:** 409
>
> **Message:** "Cannot delete resource that is in use"
>
> **Causes:**
>
> * Deleting position assigned to events
> * Deleting user with pending invitations
>
> **Solutions:**
>
> 1. Remove references before deleting
> 2. Archive instead of delete

***

## Webhook Errors

> [accordion] invalid\_webhook\_signature
>
> **HTTP Status:** 401
>
> **Message:** "Webhook signature verification failed"
>
> **Causes:**
>
> * Wrong webhook secret
> * Request body modified in transit
> * Replay attack (timestamp too old)
>
> **Solutions:**
>
> 1. Verify webhook secret matches service dashboard
> 2. Ensure raw body is used for signature verification
> 3. Check system clock is synchronized

> [accordion] webhook\_processing\_failed
>
> **HTTP Status:** 500
>
> **Message:** "Failed to process webhook event"
>
> **Causes:**
>
> * Database error during processing
> * Required data missing in webhook payload
>
> **Solutions:**
>
> 1. Check API logs for detailed error
> 2. Verify webhook payload format
> 3. Most webhooks auto-retry on failure

***

## Rate Limiting

> [accordion] rate\_limit\_exceeded
>
> **HTTP Status:** 429
>
> **Message:** "Too many requests"
>
> **Response headers:**
>
> ```
> X-RateLimit-Limit: 100
> X-RateLimit-Remaining: 0
> X-RateLimit-Reset: 1623456789
> ```
>
> **Solutions:**
>
> 1. Implement exponential backoff
> 2. Cache responses where possible
> 3. Batch requests when possible
> 4. Wait until `X-RateLimit-Reset` timestamp
>
> ```javascript theme={null}
> // Exponential backoff
> const delay = Math.pow(2, retryCount) * 1000;
> await new Promise(r => setTimeout(r, delay));
> ```

***

## External Service Errors

> [accordion] stripe\_error
>
> **HTTP Status:** 502
>
> **Message:** "Payment service error"
>
> **Causes:**
>
> * Stripe API unavailable
> * Invalid Stripe API key
> * Card declined
>
> **Solutions:**
>
> 1. Check Stripe status page
> 2. Verify Stripe API keys
> 3. Check card details for decline reason

> [accordion] twilio\_error
>
> **HTTP Status:** 502
>
> **Message:** "SMS service error"
>
> **Causes:**
>
> * Twilio API unavailable
> * Invalid phone number
> * Insufficient Twilio balance
>
> **Solutions:**
>
> 1. Check Twilio status page
> 2. Verify phone number format (E.164)
> 3. Check Twilio account balance

> [accordion] clerk\_error
>
> **HTTP Status:** 502
>
> **Message:** "Authentication service error"
>
> **Causes:**
>
> * Clerk API unavailable
> * Invalid Clerk configuration
>
> **Solutions:**
>
> 1. Check Clerk status page
> 2. Verify Clerk API keys
> 3. Retry after brief delay

***

## Debugging Tips

### Enable Verbose Logging

```bash theme={null}
# cURL with verbose output
curl -v -H "Authorization: Bearer $TOKEN" \
  http://localhost:4000/api/v1/events

# Check response headers and body
```

### Check API Logs

```bash theme={null}
# Docker logs
docker compose logs -f api

# Filter for errors
docker compose logs api | grep -i error
```

### Validate Request

```bash theme={null}
# Test with minimal request
curl -X POST \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Test Event", "date": "2024-12-01T19:00:00Z"}' \
  http://localhost:4000/api/v1/events
```

***

## Getting Help

If you encounter an error not listed here:

1. Check the API logs for detailed error messages
2. Search the [Troubleshooting](https://docs.soundchecklive.io/reference/troubleshooting.md) guide
3. Check [GitHub Issues](https://github.com/soundchecklive) for known issues
4. Ask in Slack `#soundcheck-dev` with:
   * Error code and message
   * Request details (endpoint, method, body)
   * Steps to reproduce


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.