Error Handling
TruthVouch uses standard HTTP status codes and structured error responses. All SDKs provide typed exceptions for error handling.
Error Response Format
All errors follow this structure:
{ "error": { "code": "VALIDATION_ERROR", "message": "Invalid request payload", "statusCode": 400, "details": [ { "field": "response", "message": "response is required" } ], "requestId": "req_1234567890abcdef" }}Fields:
code— Standardized error code for programmatic handlingmessage— Human-readable descriptionstatusCode— HTTP status codedetails— Field-level errors (validation errors only)requestId— Request ID for support reference
Error Codes
Client Errors (4xx)
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
INVALID_REQUEST | 400 | Malformed request (missing body, invalid JSON) | Check request format |
VALIDATION_ERROR | 422 | Invalid field values | Check details array for per-field errors |
INVALID_API_KEY | 401 | API key missing, invalid, or revoked | Verify key in Settings → API Keys |
INSUFFICIENT_PERMISSIONS | 403 | API key lacks permission for this operation | Check subscription tier |
RESOURCE_NOT_FOUND | 404 | Resource doesn’t exist | Verify resource ID |
RESOURCE_ALREADY_EXISTS | 409 | Duplicate resource creation attempt | Check if resource already exists |
RATE_LIMIT_EXCEEDED | 429 | Too many requests | Wait and retry (see Retry-After header) |
Server Errors (5xx)
| Code | HTTP | Meaning | Resolution |
|---|---|---|---|
INTERNAL_ERROR | 500 | Unexpected server error | Retry with exponential backoff |
SERVICE_UNAVAILABLE | 503 | Maintenance or outage | Check status page |
Governance Errors
| Code | HTTP | Meaning |
|---|---|---|
POLICY_BLOCKED | 403 | Request blocked by governance policy |
PII_DETECTED | 403 | PII detected and policy blocks request |
INJECTION_ATTEMPT_DETECTED | 403 | Prompt injection detected and blocked |
Example Errors
Validation Error
Request:
curl -X POST https://api.truthvouch.com/api/v1/governance/scan \ -H "Authorization: Bearer tv_live_..." \ -H "Content-Type: application/json" \ -d '{"prompt": "Tell me..."}' # missing "response"Response (422):
{ "error": { "code": "VALIDATION_ERROR", "message": "Validation failed", "statusCode": 422, "details": [ { "field": "response", "message": "response is required" } ], "requestId": "req_abc123" }}Authentication Error
Request:
curl -H "Authorization: Bearer invalid_key" \ https://api.truthvouch.com/api/v1/alertsResponse (401):
{ "error": { "code": "INVALID_API_KEY", "message": "Invalid or expired API key", "statusCode": 401, "requestId": "req_def456" }}Rate Limit Error
Response (429):
{ "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Rate limit exceeded: 1000 requests per minute", "statusCode": 429, "requestId": "req_ghi789" }}Plus headers:
Retry-After: 60X-RateLimit-Remaining: 0X-RateLimit-Reset: 1678886460Policy Blocked Error
Response (403):
{ "error": { "code": "POLICY_BLOCKED", "message": "Request blocked by governance policy", "statusCode": 403, "requestId": "req_jkl012" }, "governance": { "verdict": "blocked", "policy_id": "policy_123", "violation_reason": "Suspected hallucination detected" }}Error Handling by SDK
Python
from truthvouch import ( TruthVouchClient, PolicyBlockedError, AuthenticationError, RateLimitError, TruthVouchError,)
try: response = await client.openai.chat.completions.create(...)except PolicyBlockedError as e: # Request was blocked by policy print(f"Blocked: {e.governance_report.policy_id}")except RateLimitError as e: # Rate limit exceeded print(f"Retry after: {e.retry_after}s")except AuthenticationError as e: # Invalid API key print(f"Auth failed: {e}")except TruthVouchError as e: # Generic error print(f"Error: {e}")TypeScript
import TruthVouch, { PolicyBlockedError, AuthenticationError, RateLimitError,} from '@truthvouch/sdk';
try { const response = await tv.openai.chat.completions.create({...});} catch (error) { if (error instanceof PolicyBlockedError) { console.log(`Blocked: ${error.governanceReport.policyId}`); } else if (error instanceof RateLimitError) { console.log(`Retry after: ${error.retryAfter}s`); } else if (error instanceof AuthenticationError) { console.log(`Auth failed: ${error.message}`); } else { console.error(`Error: ${error}`); }}.NET
try{ var response = await client.Chat.CreateAsync(request, ct);}catch (GovernancePolicyViolationException ex){ _logger.LogWarning("Blocked by policy: {PolicyId}", ex.GovernanceReport?.PolicyId);}catch (TruthVouchAuthException ex){ _logger.LogError("Auth failed: {RequestId}", ex.RequestId);}catch (QuotaExceededException ex){ _logger.LogWarning("Rate limited, retry after {Seconds}s", ex.RetryAfterSeconds);}catch (TruthVouchException ex){ _logger.LogError("Error [{Code}]: {Message}", ex.ErrorCode, ex.Message);}Retry Strategy
Idempotent Requests
Safe to retry (GET, POST with idempotency key):
- 429 (Rate Limit) — retry with backoff
- 500 (Server Error) — retry with backoff
- 503 (Service Unavailable) — retry with longer backoff
Non-Idempotent Requests
Do not retry without an idempotency key:
- POST without idempotency key — risk duplicate resources
- PATCH/PUT — may cause unintended side effects
- DELETE — may delete multiple times
Use Idempotency-Key header to safely retry:
curl -X POST https://api.truthvouch.com/api/v1/governance/scan \ -H "Authorization: Bearer tv_live_..." \ -H "Idempotency-Key: req_abc123_scan_1" \ -d '{"prompt":"...","response":"..."}'Same idempotency key in retries ensures the request is processed only once.
Exponential Backoff
Implement backoff for transient errors:
import timeimport random
def retry_with_backoff(func, max_retries=5): for attempt in range(max_retries): try: return func() except (RateLimitError, ConnectionError) as e: if attempt == max_retries - 1: raise
wait_time = (2 ** attempt) + random.uniform(0, 1) print(f"Retry {attempt+1}/{max_retries} after {wait_time:.1f}s") time.sleep(wait_time)
# SDKs do this automatically with max_retries parameterHandling Specific Scenarios
401 Unauthorized
Causes:
- Invalid API key
- Expired JWT token
- Key has been revoked
Solutions:
- Verify API key is correct
- For JWT tokens, refresh using refresh token
- Check if key has been deleted in Settings → API Keys
- Generate a new API key if needed
403 Forbidden
Causes:
- Insufficient permissions (subscription tier too low)
- Governance policy violation
- Organization doesn’t have access to this feature
Solutions:
- Check subscription tier (Settings → Billing)
- If policy blocked, review governance policy
- Contact support for permission issues
429 Rate Limited
Causes:
- Exceeded rate limit for your tier
Solutions:
- Wait and retry (see
Retry-Afterheader) - Reduce request frequency
- Use batch APIs for bulk operations
- Upgrade to higher tier if persistent
503 Service Unavailable
Causes:
- Maintenance window
- Service outage
- Cloud provider issue
Solutions:
- Check status page
- Implement exponential backoff retry
- Contact support if outage persists >15 minutes