← Back to Platform Architecture
Error Handling
Overview
All Stratum Platform API errors follow a consistent response format. This document defines error types, HTTP status codes, and recovery strategies.
Error Response Format
All error responses use this envelope:
{
"status": 400,
"error": {
"type": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"field": "narrative_content",
"constraint": "required",
"value": null
}
},
"timestamp": "2026-04-14T12:30:45Z",
"request_id": "req-abc123"
}
Fields:
status — HTTP status code
error.type — Error type code (machine-readable)
error.message — Human-readable message
error.details — Context-specific details (varies by error type)
timestamp — UTC timestamp when error occurred
request_id — Unique request ID for logging/support reference
Error Types by Category
Authentication Errors (401, 403)
| Type | Code | Message | Cause | Recovery |
| Unauthorized | 401 | Missing or invalid X-User-Id header | X-User-Id header missing or user not found | Add valid X-User-Id header; verify user ID exists |
| Forbidden | 403 | Insufficient permissions for this operation | User role doesn't permit action (e.g., non-admin on admin endpoint) | Use appropriate role or request admin privilege |
| Forbidden | 403 | Cross-tenant access not permitted | Attempting to access another tenant's data | Verify tenant_id in request matches authenticated tenant |
Validation Errors (400, 422)
| Type | Code | Message | Cause | Recovery |
| Bad Request | 400 | Missing required field: {field} | Required field not provided in request body | Add field with valid value |
| Bad Request | 400 | Invalid field type: {field} (expected {type}, got {actual}) | Field type doesn't match schema (e.g., string instead of number) | Convert value to correct type |
| Bad Request | 400 | Malformed JSON in request body | JSON syntax error (trailing comma, unmatched quotes, etc.) | Fix JSON syntax; validate with JSON linter |
| Unprocessable Entity | 422 | PHI detected in request: {identifier_type} | Request contains Protected Health Information (SSN, MRN, phone, email, name) | Remove PHI; use deidentified values only |
| Unprocessable Entity | 422 | Validation gate failure: {gate_code} | PR-U blocking gate prevented submission | Review gate message; add required evidence or clarification |
| Unprocessable Entity | 422 | SUD confidentiality violation | Substance Use Disorder data without proper consent/restrictions | Add consent documentation or use restricted sharing mode |
Resource Errors (404, 409)
| Type | Code | Message | Cause | Recovery |
| Not Found | 404 | Resource not found: {resource_type} {id} | Resource doesn't exist or is archived | Verify resource ID; check if archived (/list?include_archived=true) |
| Not Found | 404 | Precedent version not found: {version} | Requested precedent version doesn't exist | Use current version or earlier existing version |
| Conflict | 409 | Resource already exists: {identifier} | Attempting to create duplicate (e.g., unique constraint violation) | Verify UNIQUE constraint columns; use PATCH to update instead |
Payment/Credit Errors (402)
| Type | Code | Message | Cause | Recovery |
| Payment Required | 402 | Insufficient credits for marketplace query | Tenant balance < query cost | Purchase credits; reduce query scope; use free endpoints |
Response includes:
{
"status": 402,
"error": {
"type": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits for marketplace query",
"details": {
"balance": 50,
"cost": 150,
"shortfall": 100,
"action": "Purchase 100+ additional credits to proceed"
}
}
}
Server Errors (500, 503)
| Type | Code | Message | Cause | Recovery |
| Internal Server Error | 500 | An unexpected error occurred | Server bug, unhandled exception | Contact support with request_id; check status page |
| Service Unavailable | 503 | Database connection failed | Database down, connection pool exhausted | Retry after 30 seconds; check database status |
PHI (Protected Health Information) Detection
The API rejects requests containing 18 Protected Health Identifiers per HIPAA Safe Harbor (45 CFR §164.514):
- Name — Any part of name
- Address — Street, city, zip code (except state)
- Phone number — All formats
- Email address — All email addresses
- Social Security Number — 9-digit format
- Medical Record Number — MRN pattern
- Health Plan Beneficiary Number — Insurance ID
- Account Number — Any financial/billing account
- Device Identifiers and Serial Numbers — Implant IDs
- Web URLs — Personal website URLs
- Biometric Records — Fingerprints, voice recordings
- License Plate Numbers — Vehicle IDs
- Relative Dates — Birth/death/admission/discharge dates (except year)
- Geographic Information — Census block, precision <state level
- IP Address — Any IP address
- Photograph/Image — Any identifying photo
- Vehicle Registration — License plate, VIN
- Passport/Visa Number — Travel document numbers
When PHI is detected: Request returns 422 Unprocessable Entity
{
"status": 422,
"error": {
"type": "PHI_VIOLATION",
"message": "PHI detected in request",
"details": {
"identifiers": ["email_address", "phone_number"],
"action": "Remove protected identifiers and resubmit"
}
}
}
Debugging Strategies
1. Check request_id
Every error response includes request_id. Use this to correlate with server logs:
# Log with request_id for support team
curl -i https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123" \
-H "Content-Type: application/json" \
-d '{"status": "invalid"}'
Response includes: "request_id": "req-abc123xyz"
Provide this ID to support team for fast lookup
2. Validate JSON
Use online JSON validator or curl with structured output:
# Pretty-print response for readability
curl -s -H "Content-Type: application/json" \
-d @request.json \
https://stratum-platform-api.fly.dev/api/appeals | jq
Check syntax before sending
python -m json.tool request.json
3. Check Required Fields
Consult endpoint documentation for required fields. Example for POST /appeals:
Required: denial_type, narrative_content
Optional: precedent_ids, evidence_attachments
4. Verify Authentication
Always include X-User-Id header:
curl -i https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123"
5. Check PHI Content
Scan request for any Protected Health Information:
# Bad: Contains email (PHI)
{
"appeal": {
"patient_contact": "john.doe@example.com",
"narrative": "..."
}
}
Good: PHI removed
{
"appeal": {
"narrative": "..."
}
}
Common Error Scenarios
Scenario 1: 400 Bad Request — Missing Field
# Request (BROKEN)
curl -X POST https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"denial_type": "NOT_MEDICALLY_NECESSARY"
}'
Response: 400
{
"status": 400,
"error": {
"type": "VALIDATION_ERROR",
"message": "Missing required field",
"details": {
"field": "narrative_content",
"constraint": "required"
}
}
}
Fix: Add missing field
curl -X POST https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"denial_type": "NOT_MEDICALLY_NECESSARY",
"narrative_content": "Patient has met criteria for level of care..."
}'
Scenario 2: 401 Unauthorized — Missing Header
# Request (BROKEN - no auth header)
curl -X GET https://stratum-platform-api.fly.dev/api/appeals
Response: 401
{
"status": 401,
"error": {
"type": "UNAUTHORIZED",
"message": "Missing X-User-Id header"
}
}
Fix: Add header
curl -X GET https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123"
Scenario 3: 422 Unprocessable Entity — PHI Detected
# Request (BROKEN - contains email PHI)
curl -X POST https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"narrative_content": "Patient john.smith@email.com presented with depression symptoms..."
}'
Response: 422
{
"status": 422,
"error": {
"type": "PHI_VIOLATION",
"message": "PHI detected in request",
"details": {
"identifiers": ["email_address"]
}
}
}
Fix: Remove PHI
curl -X POST https://stratum-platform-api.fly.dev/api/appeals \
-H "X-User-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"narrative_content": "Patient presented with depression symptoms and functional impairment..."
}'
Scenario 4: 402 Payment Required — Insufficient Credits
# Request (marketplace query costs credits)
curl -X POST https://stratum-platform-api.fly.dev/api/marketplace/query \
-H "X-User-Id: user-123" \
-H "Content-Type: application/json" \
-d '{
"payer_id": "cigna-commercial",
"denial_code": "NOT_MEDICALLY_NECESSARY"
}'
Response: 402
{
"status": 402,
"error": {
"type": "INSUFFICIENT_CREDITS",
"message": "Insufficient credits for marketplace query",
"details": {
"balance": 25,
"cost": 150,
"shortfall": 125
}
}
}
Fix: Use free endpoint (payer-registry) or purchase credits
curl -X GET https://stratum-platform-api.fly.dev/api/registries/payer-registry \
-H "X-User-Id: user-123"
See Also
07-GOVERNANCE/API-TROUBLESHOOTING.md — Detailed troubleshooting guide with common errors and solutions
OVERVIEW.md — API design philosophy and status codes
AUTHENTICATION.md — Authentication headers and Phase 1/Phase 2 migration
ENDPOINTS-VALIDATION.md — Validation gate error codes (PR-U, PR-D)