Skip to content

Error Handling

The Mantis API returns structured error responses following a consistent format. This guide covers all error codes, their meanings, and how to resolve them.

All errors follow this JSON structure:

{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error description",
"details": {
// Optional: Additional context (only for specific errors)
}
}
}

Fields:

  • code - Machine-readable error identifier (constant)
  • message - Human-readable description (may vary)
  • details - Optional additional context
Status CodeMeaningUsage
400Bad RequestValidation errors, malformed requests
401UnauthorizedMissing or invalid authentication
403ForbiddenInsufficient permissions, access denied
404Not FoundResource doesn’t exist
409ConflictDuplicate resource, constraint violation
429Too Many RequestsRate limit exceeded
500Internal Server ErrorUnexpected server-side error
503Service UnavailableExternal service (database, queue) unavailable

HTTP Status: 401

Description: General authentication failure.

Example:

{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
}

Causes:

  • No Authorization header provided
  • Empty authorization header

Resolution: Include the Authorization: Bearer <token> header in your request.


HTTP Status: 401

Description: Invalid email/password combination or API key.

Example:

{
"error": {
"code": "INVALID_CREDENTIALS",
"message": "Invalid credentials"
}
}

Causes:

  • Wrong email or password
  • Account is inactive or suspended
  • API key is revoked or expired

Resolution:

  • Verify credentials are correct
  • Check account status with administrator
  • Create a new API key if expired

HTTP Status: 401

Description: JWT access token has expired.

Example:

{
"error": {
"code": "TOKEN_EXPIRED",
"message": "Token expired"
}
}

Resolution:

  • Call POST /auth/refresh to get a new access token
  • Implement automatic token refresh in your client

HTTP Status: 401

Description: Token is malformed or signature is invalid.

Example:

{
"error": {
"code": "INVALID_TOKEN",
"message": "Invalid token: Invalid user ID in token"
}
}

Causes:

  • Malformed JWT structure
  • Invalid signature (wrong secret key)
  • Token was modified after signing
  • Token audience/issuer mismatch

Resolution:

  • Login again to get a fresh token
  • Verify you’re connecting to the correct Mantis server

HTTP Status: 401

Description: The Authorization header is missing.

Example:

{
"error": {
"code": "MISSING_AUTH_HEADER",
"message": "Missing authorization header"
}
}

Resolution: Add the header:

Terminal window
Authorization: Bearer <your-token>

HTTP Status: 401

Description: The Authorization header format is incorrect.

Example:

{
"error": {
"code": "INVALID_AUTH_HEADER",
"message": "Invalid authorization header format"
}
}

Causes:

  • Missing “Bearer” prefix
  • Extra spaces or special characters
  • Incorrect encoding

Valid format:

Authorization: Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImN1cnJlbnQifQ...

HTTP Status: 403

Description: Pending 2FA token used on a protected endpoint.

Example:

{
"error": {
"code": "TWO_FACTOR_REQUIRED",
"message": "Two-factor authentication required"
}
}

Cause: You received a pending_token from login and tried to use it on a regular endpoint.

Resolution: Complete the 2FA flow by calling POST /auth/2fa/verify first.

HTTP Status: 403

Description: Access denied with specific reason.

Example:

{
"error": {
"code": "FORBIDDEN",
"message": "Access denied: Account is suspended"
}
}

Causes:

  • Account status is not “active”
  • Tenant-specific access restrictions
  • Resource belongs to a different tenant

Resolution: Contact your administrator to check account status and permissions.


HTTP Status: 403

Description: User lacks required role or permission.

Example:

{
"error": {
"code": "INSUFFICIENT_PERMISSIONS",
"message": "Insufficient permissions"
}
}

Causes:

  • Missing required role (e.g., “admin”, “operator”)
  • Missing required permission (e.g., “deployments:create”)
  • Tenant isolation prevents access

Resolution:

  • Request the required role from your administrator
  • Verify you’re in the correct tenant context

HTTP Status: 400

Description: Request data failed validation rules.

Example:

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed: email: Invalid email format"
}
}

Causes:

  • Missing required fields
  • Invalid field formats (email, UUID, etc.)
  • Out-of-range values
  • Field length constraints violated

Resolution: Review the validation message and fix the request body.

Common validation rules:

  • Email must be valid format
  • UUIDs must be properly formatted
  • Pagination: page >= 1, limit between 1-100
  • Names typically 1-255 characters

HTTP Status: 400

Description: Request body is not valid JSON.

Example:

{
"error": {
"code": "INVALID_BODY",
"message": "Invalid request body: expected value at line 1 column 1"
}
}

Causes:

  • Malformed JSON syntax
  • Missing closing braces/brackets
  • Wrong encoding

Resolution: Validate your JSON with a linter before sending.


HTTP Status: 400

Description: Required field is missing from request.

Example:

{
"error": {
"code": "MISSING_FIELD",
"message": "Missing required field: solution_id"
}
}

Resolution: Add the missing field to your request body.

HTTP Status: 404

Description: Requested resource doesn’t exist.

Example:

{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found: Deployment not found"
}
}

Causes:

  • Invalid resource ID
  • Resource was deleted
  • Tenant isolation (resource exists but in different tenant)
  • Resource never existed

Resolution:

  • Verify the resource ID is correct
  • Check if the resource was deleted
  • Confirm you’re in the correct tenant

HTTP Status: 409

Description: Resource already exists or constraint violated.

Example:

{
"error": {
"code": "CONFLICT",
"message": "Resource already exists: User with email test@example.com already exists"
}
}

Causes:

  • Unique constraint violation (duplicate email, username, name)
  • Foreign key constraint violation
  • Check constraint violation

Resolution:

  • Use a different unique identifier
  • Delete the existing resource first (if appropriate)
  • Update the existing resource instead of creating a new one

HTTP Status: 409

Description: Deployment is blocked by an active deployment freeze.

Example:

{
"error": {
"code": "DEPLOYMENT_FROZEN",
"message": "Deployment blocked by active freeze",
"details": {
"active_freezes": [
{
"id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
"name": "Production Freeze",
"ends_at": "2024-12-26T23:59:59Z"
}
],
"can_override": false
}
}
}

Causes:

  • Active freeze targeting the environment or tags
  • Insufficient permissions to override freeze

Resolution:

  • Wait until freeze ends
  • Request override permission from administrator
  • Use the override_freeze: true parameter (if you have override permission)

Mantis has two independent rate limiters. They return different bodies, so handle both by status code (429) rather than by parsing a specific JSON shape.

HTTP Status: 429

Description: Per-client-IP limit exceeded (100 requests/second sustained, burst 200).

The body is plain text, not JSON:

Rate limit exceeded. Please try again later.

Response headers:

Retry-After: 1
X-RateLimit-Remaining: 0

Authentication limiter (AUTH_RATE_LIMIT_EXCEEDED)

Section titled “Authentication limiter (AUTH_RATE_LIMIT_EXCEEDED)”

HTTP Status: 429

Description: Too many authentication attempts (5 login attempts/minute per IP). Exceeding the limit triggers a temporary lockout.

The body is JSON:

{
"error": {
"code": "AUTH_RATE_LIMIT_EXCEEDED",
"message": "Too many authentication attempts",
"retry_after_secs": 900,
"reason": "too_many_attempts"
}
}

Response headers:

Retry-After: 900
X-RateLimit-Remaining: 0
Content-Type: application/json

Resolution:

  • Honor the Retry-After header before retrying
  • Implement exponential backoff in your client
  • Reduce request frequency
  • Contact your administrator if you need higher general limits

HTTP Status: 500

Description: Database operation failed.

Example:

{
"error": {
"code": "DATABASE_ERROR",
"message": "A database error occurred"
}
}

Causes:

  • Database server is down
  • Query timeout
  • Database corruption (rare)

Resolution:

  • Retry the request
  • Contact administrator if persistent

HTTP Status: 500

Description: Cannot establish database connection.

Example:

{
"error": {
"code": "DATABASE_CONNECTION_ERROR",
"message": "Database connection error: connection pool exhausted"
}
}

Causes:

  • Database server unreachable
  • Connection pool exhausted
  • Network issues

Resolution:

  • Wait and retry
  • Contact administrator for infrastructure issues

HTTP Status: 500

Description: Unexpected server error.

Example:

{
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error"
}
}

Resolution:

  • Retry the request
  • Report to administrator with request details
  • Check server logs if you have access

HTTP Status: 503

Description: External service is unavailable.

Example:

{
"error": {
"code": "SERVICE_UNAVAILABLE",
"message": "Service unavailable: Orchestration service unreachable"
}
}

Causes:

  • Thorax (gRPC orchestration service) is down
  • RabbitMQ message queue is unavailable
  • Redis cache is down

Resolution:

  • Check service health endpoints
  • Contact administrator for infrastructure issues

HTTP Status: 500

Description: External service returned an error.

Example:

{
"error": {
"code": "EXTERNAL_SERVICE_ERROR",
"message": "External service error: Failed to dispatch deployment"
}
}

Resolution:

  • Retry the request
  • Check external service status
  • Contact administrator if persistent

HTTP Status: 500

Description: Server configuration is invalid.

Example:

{
"error": {
"code": "CONFIGURATION_ERROR",
"message": "Configuration error: Invalid JWT secret"
}
}

Resolution: Contact your administrator immediately. This indicates a server misconfiguration.

  1. Check token format:

    Terminal window
    # Decode JWT (without verification) to inspect claims
    echo "eyJhbGciOiJFUzI..." | cut -d'.' -f2 | base64 -d 2>/dev/null | jq
  2. Verify token expiration:

    const token = 'eyJhbGci...';
    const payload = JSON.parse(atob(token.split('.')[1]));
    console.log('Expires at:', new Date(payload.exp * 1000));
  3. Test with curl:

    Terminal window
    curl -v https://mantis.example.com/api/v1/auth/me \
    -H "Authorization: Bearer $TOKEN"

JavaScript/TypeScript:

async function handleApiCall(url: string, token: string) {
const response = await fetch(url, {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
const error = await response.json();
switch (error.error.code) {
case 'TOKEN_EXPIRED':
// Trigger token refresh
await refreshToken();
return handleApiCall(url, newToken); // Retry
case 'INSUFFICIENT_PERMISSIONS':
// Show permission error to user
showError("You don't have permission for this action");
break;
case 'NOT_FOUND':
// Handle missing resource
return null;
default:
throw new Error(error.error.message);
}
}
return response.json();
}

Python:

import requests
from typing import Optional, Dict, Any
def handle_api_error(response: requests.Response) -> None:
"""Parse and handle API error responses."""
if response.status_code == 401:
error = response.json()
if error['error']['code'] == 'TOKEN_EXPIRED':
# Trigger token refresh
raise TokenExpiredError()
raise AuthenticationError(error['error']['message'])
elif response.status_code == 403:
raise PermissionError('Insufficient permissions')
elif response.status_code == 404:
return None # Resource not found
elif response.status_code >= 500:
raise ServiceError('Server error, please retry')
response.raise_for_status()