MATIH Platform is in active MVP development. Documentation reflects current implementation status.
20. Appendices & Reference
Error Codes & Status Codes

Error Codes and Status Codes

This section provides a comprehensive reference for all HTTP status codes, custom error codes, and error response structures used across the MATIH Enterprise Platform. Every service follows the same error conventions, making it possible to write consistent error handling logic in client applications regardless of which service is being called.


HTTP Status Code Usage

The MATIH Platform uses standard HTTP status codes consistently across all services. The following table documents the precise meaning of each status code within the platform context.

2xx Success Codes

CodeReason PhraseUsage
200OKSuccessful GET, PUT, PATCH, or DELETE request
201CreatedSuccessful POST request that created a new resource
202AcceptedRequest accepted for asynchronous processing (e.g., pipeline trigger, async query, tenant provisioning)
204No ContentSuccessful DELETE request with no response body

3xx Redirection Codes

CodeReason PhraseUsage
301Moved PermanentlyAPI endpoint has been permanently moved to a new URL
302FoundOAuth2/SAML redirect during SSO authentication flow
304Not ModifiedResource has not changed since the last request (ETag/If-None-Match)
307Temporary RedirectOAuth2 callback redirect during authentication

4xx Client Error Codes

CodeReason PhraseUsage
400Bad RequestRequest body validation failed, malformed JSON, missing required fields
401UnauthorizedMissing, expired, or invalid JWT token
403ForbiddenValid token but insufficient permissions (RBAC or OPA policy denial)
404Not FoundResource does not exist or is not accessible to the current tenant
405Method Not AllowedHTTP method not supported for this endpoint
409ConflictResource state conflict (e.g., duplicate slug, concurrent update, already exists)
410GoneResource has been permanently deleted
413Payload Too LargeRequest body exceeds maximum allowed size
415Unsupported Media TypeContent-Type header is not application/json (or multipart for file uploads)
422Unprocessable EntityRequest is syntactically valid but semantically incorrect (e.g., invalid SQL, invalid pipeline DAG)
429Too Many RequestsRate limit exceeded; check Retry-After header

5xx Server Error Codes

CodeReason PhraseUsage
500Internal Server ErrorUnexpected server-side error; details logged for debugging
502Bad GatewayUpstream service (LLM provider, database, Kafka) is unreachable
503Service UnavailableService is starting up, shutting down, or temporarily overloaded
504Gateway TimeoutUpstream request exceeded the configured timeout

Standard Error Response Structure

All MATIH services return errors in a consistent JSON structure. This allows client applications to implement a single error-handling layer that works across all services.

Error Response Schema

{
  "error": {
    "code": "string",
    "message": "string",
    "details": "string | null",
    "field": "string | null",
    "timestamp": "string (ISO 8601)",
    "requestId": "string",
    "path": "string",
    "traceId": "string | null"
  }
}
FieldTypeDescription
codestringPlatform-specific error code (e.g., MATIH-IAM-1001)
messagestringHuman-readable error message suitable for display
detailsstring or nullAdditional technical details (included in non-production environments)
fieldstring or nullSpecific field name that caused a validation error
timestampstringISO 8601 timestamp of when the error occurred
requestIdstringUnique request identifier for correlation with logs
pathstringThe API path that produced the error
traceIdstring or nullOpenTelemetry trace ID for distributed tracing

Validation Error Response (Multiple Fields)

When a request fails validation on multiple fields, the response includes an errors array:

{
  "error": {
    "code": "MATIH-COMMON-1000",
    "message": "Validation failed",
    "timestamp": "2026-02-12T10:30:00.000Z",
    "requestId": "req-abc123",
    "path": "/api/v1/tenants",
    "errors": [
      {
        "field": "slug",
        "message": "Slug must be lowercase alphanumeric with hyphens",
        "rejectedValue": "Acme Corp!"
      },
      {
        "field": "adminEmail",
        "message": "Must be a valid email address",
        "rejectedValue": "not-an-email"
      },
      {
        "field": "plan",
        "message": "Must be one of: FREE, STARTER, PROFESSIONAL, ENTERPRISE",
        "rejectedValue": "PLATINUM"
      }
    ]
  }
}

Custom Error Code Format

MATIH custom error codes follow the pattern:

MATIH-{SERVICE}-{NUMBER}
ComponentDescriptionExample
MATIHPlatform prefix (always present)MATIH
{SERVICE}Service abbreviation (3-6 characters)IAM, TENANT, AI, ML, QUERY, BI
{NUMBER}Four-digit error number1001, 2003, 5001

Number ranges have semantic meaning:

RangeCategory
1000-1999Authentication and authorization errors
2000-2999Resource validation and business rule errors
3000-3999Data access and persistence errors
4000-4999External service and integration errors
5000-5999System and infrastructure errors
6000-6999Rate limiting, quota, and billing errors
7000-7999Configuration and feature flag errors

Per-Service Error Catalogs

IAM Service Error Codes

CodeHTTP StatusMessageDescription
MATIH-IAM-1001401Authentication token has expiredJWT access token has passed its expiration time
MATIH-IAM-1002401Invalid authentication tokenJWT signature verification failed
MATIH-IAM-1003401Authentication token is malformedToken does not conform to JWT structure
MATIH-IAM-1004401Missing authentication tokenNo Authorization header provided
MATIH-IAM-1005401Refresh token has expiredRefresh token TTL exceeded
MATIH-IAM-1006401Refresh token has been revokedToken was explicitly invalidated
MATIH-IAM-1007401Invalid credentialsEmail/password combination does not match
MATIH-IAM-1008401Account is lockedToo many failed login attempts
MATIH-IAM-1009401Account is deactivatedUser account has been deactivated by admin
MATIH-IAM-1010401MFA challenge requiredMFA is enabled; submit MFA code to proceed
MATIH-IAM-1011401Invalid MFA codeMFA verification code is incorrect
MATIH-IAM-1012401MFA code has expiredTOTP code has expired (30-second window)
MATIH-IAM-1050403Insufficient permissionsUser does not have the required role/permission
MATIH-IAM-1051403Tenant access deniedUser does not belong to the requested tenant
MATIH-IAM-1052403Resource access denied by policyOPA policy evaluation returned deny
MATIH-IAM-2001409Email already registeredA user with this email already exists in the tenant
MATIH-IAM-2002400Password does not meet requirementsPassword complexity rules not satisfied
MATIH-IAM-2003400Invalid role assignmentSpecified role does not exist or cannot be assigned
MATIH-IAM-2004404User not foundNo user exists with the specified ID
MATIH-IAM-2005404Role not foundNo role exists with the specified ID
MATIH-IAM-4001502OAuth2 provider unreachableCannot connect to external identity provider
MATIH-IAM-4002400OAuth2 state mismatchCSRF protection: state parameter does not match
MATIH-IAM-4003400OAuth2 authorization code expiredCode was not exchanged within the allowed window
MATIH-IAM-4004502SAML assertion validation failedSAML response signature or certificate is invalid

Tenant Service Error Codes

CodeHTTP StatusMessageDescription
MATIH-TENANT-2001409Tenant slug already existsThe requested slug is taken by another tenant
MATIH-TENANT-2002400Invalid tenant slug formatSlug must be 3-63 lowercase alphanumeric with hyphens
MATIH-TENANT-2003422Tenant provisioning in progressCannot modify tenant while provisioning is active
MATIH-TENANT-2004404Tenant not foundNo tenant with the specified ID or slug
MATIH-TENANT-2005409Tenant already activeCannot activate a tenant that is already active
MATIH-TENANT-2006409Tenant is suspendedOperation not allowed on suspended tenant
MATIH-TENANT-2010400Invalid connector configurationConnector config validation failed
MATIH-TENANT-2011404Connector not foundSpecified connector does not exist
MATIH-TENANT-2012422Connector test failedConnection test to data source failed
MATIH-TENANT-2013409Connector name already existsDuplicate connector name within tenant
MATIH-TENANT-3001500Namespace creation failedKubernetes namespace could not be created
MATIH-TENANT-3002500Secret provisioning failedKubernetes secrets could not be created
MATIH-TENANT-4001502DNS zone creation failedAzure DNS / Route53 / Cloud DNS API error
MATIH-TENANT-4002502Ingress controller deployment failedHelm release for NGINX failed
MATIH-TENANT-4003504LoadBalancer IP not assignedTimed out waiting for external IP assignment
MATIH-TENANT-6001403Tenant user limit exceededCannot create more users; plan limit reached
MATIH-TENANT-6002403Tenant connector limit exceededCannot create more connectors; plan limit reached
MATIH-TENANT-6003403Tenant storage limit exceededData storage quota for this plan has been reached

AI Service Error Codes

CodeHTTP StatusMessageDescription
MATIH-AI-1001401Tenant context missingX-Tenant-ID header is required for AI service calls
MATIH-AI-2001404Conversation not foundNo conversation with the specified ID
MATIH-AI-2002400Empty messageChat message cannot be empty
MATIH-AI-2003422SQL generation failedAgent could not produce valid SQL from the input
MATIH-AI-2004422SQL validation failedGenerated SQL did not pass safety or syntax checks
MATIH-AI-2005422Intent classification failedCould not determine the intent of the user query
MATIH-AI-2006422Schema not found for queryNo matching schema context for the data source
MATIH-AI-2007400Unsupported SQL dialectRequested dialect is not supported
MATIH-AI-2008400Visualization not supported for result typeCannot generate chart for the given data shape
MATIH-AI-2010404Agent not foundSpecified agent name does not exist
MATIH-AI-2011422Agent execution failedAgent raised an exception during execution
MATIH-AI-2020404Session not foundStudio session does not exist or has expired
MATIH-AI-2021400Session has expiredStudio session exceeded timeout
MATIH-AI-2030422DNN architecture invalidArchitecture validation returned errors
MATIH-AI-2031400Unsupported frameworkRequested framework is not in the supported list
MATIH-AI-4001502LLM provider unavailableCannot reach OpenAI, Anthropic, Azure OpenAI, or vLLM
MATIH-AI-4002502LLM provider rate limitedUpstream LLM API returned 429
MATIH-AI-4003504LLM provider timeoutLLM request exceeded configured timeout
MATIH-AI-4004502LLM provider returned errorLLM API returned a non-retriable error
MATIH-AI-4005502Query execution failedTrino/ClickHouse returned an error executing SQL
MATIH-AI-4006502Catalog service unavailableCannot reach the catalog service for schema retrieval
MATIH-AI-4007502Vector store unavailableQdrant is unreachable for embedding lookups
MATIH-AI-5001500Agent orchestrator internal errorUnexpected error in LangGraph execution
MATIH-AI-5002500State checkpoint failedCould not persist conversation state
MATIH-AI-6001429Token budget exceededTenant has exceeded the monthly LLM token budget
MATIH-AI-6002429Rate limit exceededToo many requests per minute from this user
MATIH-AI-6003429Concurrent request limitMaximum concurrent streaming connections reached

Query Engine Error Codes

CodeHTTP StatusMessageDescription
MATIH-QUERY-2001400SQL syntax errorQuery contains invalid SQL syntax
MATIH-QUERY-2002400Unknown catalogReferenced catalog does not exist
MATIH-QUERY-2003400Unknown schemaReferenced schema does not exist
MATIH-QUERY-2004400Unknown tableReferenced table does not exist
MATIH-QUERY-2005400Unknown columnReferenced column does not exist
MATIH-QUERY-2006422Query exceeds complexity limitQuery plan cost exceeds configured maximum
MATIH-QUERY-2007422Query exceeds row limitResult set would exceed maximum row count
MATIH-QUERY-2008400DML not allowedINSERT/UPDATE/DELETE not permitted via this endpoint
MATIH-QUERY-2009400DDL not allowedCREATE/ALTER/DROP not permitted via this endpoint
MATIH-QUERY-3001504Query execution timeoutQuery exceeded the configured execution timeout
MATIH-QUERY-3002500Query execution failedTrino returned an unexpected execution error
MATIH-QUERY-4001502Trino coordinator unreachableCannot connect to the Trino coordinator
MATIH-QUERY-4002503No Trino workers availableAll Trino workers are offline
MATIH-QUERY-5001500Result serialization failedCould not serialize query results to JSON

ML Service Error Codes

CodeHTTP StatusMessageDescription
MATIH-ML-2001404Model not foundNo model with the specified ID
MATIH-ML-2002404Model version not foundSpecified version does not exist
MATIH-ML-2003409Model name already existsDuplicate model name within tenant
MATIH-ML-2004422Invalid stage transitionModel cannot be moved to the requested stage
MATIH-ML-2005422Training configuration invalidTraining job spec has validation errors
MATIH-ML-2006404Experiment not foundNo experiment with the specified ID
MATIH-ML-2007404Deployment not foundModel serving deployment does not exist
MATIH-ML-2008409Deployment already existsModel is already deployed
MATIH-ML-2009422Prediction input schema mismatchInput does not match model's expected schema
MATIH-ML-3001500Training job submission failedCould not submit job to Ray cluster
MATIH-ML-4001502MLflow unreachableCannot connect to MLflow tracking server
MATIH-ML-4002502Ray cluster unavailableRay head node is not responding
MATIH-ML-4003502Feature store unavailableFeast online store is unreachable
MATIH-ML-4004502Model artifact download failedCannot download model from artifact store
MATIH-ML-6001429GPU quota exceededTenant has no remaining GPU quota

BI Service Error Codes

CodeHTTP StatusMessageDescription
MATIH-BI-2001404Dashboard not foundNo dashboard with the specified ID
MATIH-BI-2002409Dashboard name already existsDuplicate dashboard name in workspace
MATIH-BI-2003404Widget not foundSpecified widget does not exist on the dashboard
MATIH-BI-2004400Invalid widget configurationWidget config validation failed
MATIH-BI-2005422Filter configuration invalidDashboard filter has an invalid expression
MATIH-BI-2006400Export format not supportedRequested export format is not available
MATIH-BI-4001502Render service unavailableServer-side rendering service is unreachable
MATIH-BI-4002504Dashboard export timeoutPDF/PNG export exceeded the time limit

Common Error Codes (All Services)

CodeHTTP StatusMessageDescription
MATIH-COMMON-1000400Validation failedOne or more request fields failed validation
MATIH-COMMON-1001400Invalid JSONRequest body is not valid JSON
MATIH-COMMON-1002400Missing required fieldA required field is missing from the request
MATIH-COMMON-1003415Unsupported content typeContent-Type must be application/json
MATIH-COMMON-1004413Request body too largePayload exceeds the maximum allowed size
MATIH-COMMON-3001500Database connection failedCannot establish connection to PostgreSQL
MATIH-COMMON-3002500Database query failedSQL execution error in the service database
MATIH-COMMON-3003500Cache connection failedCannot connect to Redis
MATIH-COMMON-4001502Kafka connection failedCannot connect to Kafka bootstrap servers
MATIH-COMMON-4002502Kafka message publish failedFailed to publish message to Kafka topic
MATIH-COMMON-5001500Internal server errorUnexpected error; see logs for details
MATIH-COMMON-5002503Service starting upService is not yet ready to accept requests
MATIH-COMMON-5003503Service shutting downService is in graceful shutdown
MATIH-COMMON-6001429Rate limit exceededToo many requests; retry after the specified delay

Provisioning Error Codes

The tenant provisioning pipeline uses a dedicated ProvisioningErrorCode enum that provides structured error classification for retry logic, alerting, and operator guidance. These codes are embedded in TenantProvisioningException and are used by the provisioning metrics system for failure categorization.

Error Code Categories

CategoryCode RangeDescription
Permission & AccessPERM_001 - PERM_004Azure/K8s RBAC, missing/invalid credentials
Resource QuotaQUOTA_001 - QUOTA_004Azure subscription, K8s namespace, storage, DB connection limits
Network & ConnectivityNET_001 - NET_004DNS, timeout, TLS, private endpoint errors
Resource StateSTATE_001 - STATE_004Already exists, not found, invalid state, locked
TimeoutTIMEOUT_001 - TIMEOUT_004Operation, Helm, Terraform, migration timeouts
ConfigurationCONFIG_001 - CONFIG_004Invalid, missing, conflicting config, Helm values
External ServiceEXT_001 - EXT_004API errors, service down, rate limited, Azure throttled
DatabaseDB_001 - DB_008Permission, not found, exists, connection, operation, timeout, delete, user creation
KubernetesK8S_001 - K8S_002Client error, pod exec failed
Pod SchedulingSCHED_001 - SCHED_004Taint mismatch, node selector, autoscaler, insufficient resources
DataDATA_001 - DATA_003Validation, schema migration, integrity
ObservabilityOBS_001 - OBS_002Observability setup, metrics setup
InfrastructureINFRA_001 - INFRA_002General infrastructure, Terraform apply
InternalINT_001 - INT_004Internal error, state inconsistency, rollback failed, step execution

Each error code includes:

  • Retryable flag: Whether automatic retry is appropriate
  • Remediation guidance: Operator-facing fix instructions
  • Auto-classification: ProvisioningErrorCode.fromException(cause) maps common exception types to appropriate codes

Domain Exception Classes

Every control-plane service throws domain-specific exceptions instead of generic RuntimeException. This enables precise error classification in metrics, structured error responses, and service-specific error handling.

ServiceException ClassPackage
tenant-serviceTenantProvisioningExceptioncom.matih.tenant.exception
tenant-serviceTenantOperationExceptioncom.matih.tenant.exception
tenant-serviceTenantNotFoundExceptioncom.matih.tenant.exception
tenant-serviceTenantValidationExceptioncom.matih.tenant.exception
tenant-serviceTerraformStateExceptioncom.matih.tenant.exception
api-gatewayGatewayExceptioncom.matih.gateway.exception
infrastructure-serviceInfrastructureExceptioncom.matih.infrastructure.exception
iam-serviceAuthenticationExceptioncom.matih.iam.exception
iam-serviceBusinessExceptioncom.matih.iam.exception
iam-serviceTokenExceptioncom.matih.iam.exception
config-serviceConfigServiceExceptioncom.matih.config.exception
billing-serviceBillingExceptioncom.matih.billing.exception
audit-serviceAuditServiceExceptioncom.matih.audit.exception
notification-serviceNotificationExceptioncom.matih.notification.exception
observability-apiObservabilityExceptioncom.matih.observability.exception

All domain exceptions extend RuntimeException and provide at minimum (String message) and (String message, Throwable cause) constructors. TenantProvisioningException additionally supports a Builder pattern with error codes, tenant context, and structured error output.


Error Handling Best Practices

Client-Side Error Handling

When consuming MATIH APIs, implement error handling according to this priority:

try {
  const response = await apiClient.post('/api/v1/chat', payload);
  return response.data;
} catch (error) {
  if (error.response) {
    const { status, data } = error.response;
    const errorCode = data.error?.code;
 
    switch (status) {
      case 401:
        // Token expired or invalid - attempt refresh
        if (errorCode === 'MATIH-IAM-1001') {
          await refreshToken();
          return retry(request);
        }
        // Other 401s - redirect to login
        redirectToLogin();
        break;
 
      case 403:
        // Insufficient permissions - show access denied
        showAccessDeniedMessage(data.error.message);
        break;
 
      case 429:
        // Rate limited - retry after delay
        const retryAfter = error.response.headers['retry-after'];
        await delay(retryAfter * 1000);
        return retry(request);
 
      case 422:
        // Business logic error - show to user
        showErrorMessage(data.error.message);
        break;
 
      case 502:
      case 503:
      case 504:
        // Upstream error - retry with exponential backoff
        return retryWithBackoff(request, { maxRetries: 3 });
 
      default:
        // Unexpected error - log and show generic message
        logError(data.error);
        showGenericErrorMessage();
    }
  }
}

Server-Side Error Generation

Services should use the common error factory to generate consistent error responses:

// Java Spring Boot example
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(
    ResourceNotFoundException ex, HttpServletRequest request) {
 
    ErrorResponse error = ErrorResponse.builder()
        .code("MATIH-TENANT-2004")
        .message("Tenant not found")
        .details(ex.getMessage())
        .timestamp(Instant.now())
        .requestId(request.getHeader("X-Request-ID"))
        .path(request.getRequestURI())
        .traceId(Span.current().getSpanContext().getTraceId())
        .build();
 
    return ResponseEntity.status(404).body(error);
}
# Python FastAPI example
from fastapi import HTTPException
from datetime import datetime
 
class MatihError(HTTPException):
    def __init__(self, code: str, message: str, status_code: int,
                 details: str = None):
        self.error_code = code
        self.error_message = message
        super().__init__(
            status_code=status_code,
            detail={
                "error": {
                    "code": code,
                    "message": message,
                    "details": details,
                    "timestamp": datetime.utcnow().isoformat() + "Z"
                }
            }
        )
 
# Usage
raise MatihError(
    code="MATIH-AI-2003",
    message="SQL generation failed",
    status_code=422,
    details="Could not generate valid SQL for the given natural language query"
)

Error Monitoring and Alerting

All errors with HTTP status 500 or above are automatically:

  1. Logged with full stack trace and request context
  2. Reported to the observability stack via OpenTelemetry
  3. Aggregated in Prometheus error rate metrics
  4. Visible in Grafana error dashboards
  5. Subject to alerting rules (error rate thresholds trigger PagerDuty/Slack notifications)

The error rate SLO for each service is defined as: fewer than 0.1% of requests should return 5xx status codes, measured over a 30-minute rolling window.