Skip to content

Error Codes

All API errors return a consistent JSON format:

{
"error": "Human-readable error message",
"code": "ERROR_CODE",
"details": {}
}

The details field is optional and provides additional context for some error types.

Error codes

CodeHTTP StatusDescription
VALIDATION_ERROR400Invalid request body, missing required fields, or invalid key format
UNAUTHORIZED401Missing, invalid, or expired Bearer token
FORBIDDEN403Token lacks required permissions
NOT_FOUND404Resource does not exist
METHOD_NOT_ALLOWED405HTTP method not supported for this endpoint
CONFLICT409Resource already exists, or version conflict on update
PAYLOAD_TOO_LARGE413Request body exceeds 1MB limit
RATE_LIMITED429Rate limit exceeded
INTERNAL_ERROR500Unexpected server error

Examples

Validation error

Terminal window
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "enabled": true }' \
"https://edgeflags.net/api/v1/flags"
{
"error": "Missing required fields: key, enabled",
"code": "VALIDATION_ERROR"
}

Invalid key format

Terminal window
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "key": "INVALID KEY!", "enabled": true }' \
"https://edgeflags.net/api/v1/flags"
{
"error": "Invalid key format: must match [a-z0-9][a-z0-9._-]{0,127}",
"code": "VALIDATION_ERROR"
}

Unauthorized

Terminal window
curl "https://edgeflags.net/api/v1/flags"
{
"error": "Unauthorized",
"code": "UNAUTHORIZED"
}

Forbidden

{
"error": "Insufficient permissions",
"code": "FORBIDDEN"
}

For admin-only endpoints:

{
"error": "Admin permission required",
"code": "FORBIDDEN"
}

Not found

{
"error": "Flag not found",
"code": "NOT_FOUND"
}

Conflict — duplicate key

{
"error": "Flag already exists",
"code": "CONFLICT"
}

Conflict — version mismatch

When using If-Match for optimistic concurrency:

{
"error": "Version conflict",
"code": "CONFLICT",
"details": {
"current_version": 3
}
}

Rate limited

{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED"
}

Rate-limited responses include these headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per minute
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUnix timestamp (ms) when the window resets
Retry-AfterSeconds until the window resets

Payload too large

Returned when Content-Length exceeds 1MB for POST/PUT requests:

{
"error": "Request body too large",
"code": "PAYLOAD_TOO_LARGE"
}

Response headers

Every response includes:

HeaderDescription
X-Request-IdUnique UUID for the request (useful for debugging)
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
Referrer-Policystrict-origin-when-cross-origin
Strict-Transport-Securitymax-age=31536000; includeSubDomains