Error Contract
Status
Section titled “Status”This document is FINAL and ENFORCEABLE for all services.
1. Purpose
Section titled “1. Purpose”This document standardizes error responses across:
- Auth
- Core
- Base / Module backends
- Frontend expectations
2. Core Rule
Section titled “2. Core Rule”401 → authentication problem403 → authorization problem503 → system failureThis must be applied consistently across all services.
3. Status Code Definitions
Section titled “3. Status Code Definitions”3.1 401 — Unauthorized
Section titled “3.1 401 — Unauthorized”Used when:
- missing token
- invalid token
- expired token
- wrong issuer / audience
- token revoked
Example
Section titled “Example”{ "success": false, "error": { "code": "unauthorized", "message": "invalid or expired token" }}Frontend behavior
Section titled “Frontend behavior”- attempt token refresh
- if fails → logout
3.2 403 — Forbidden
Section titled “3.2 403 — Forbidden”Used when:
- user authenticated
- BUT:
- no membership
- module not granted
- permission missing
- delegation denied
Example
Section titled “Example”{ "success": false, "error": { "code": "forbidden", "message": "missing permission: finance.expense.create" }}Frontend behavior
Section titled “Frontend behavior”- show access denied
- optionally refresh access state
3.3 400 — Bad Request
Section titled “3.3 400 — Bad Request”Used when:
- missing
x-org - invalid
x-org - malformed request
Example
Section titled “Example”{ "success": false, "error": { "code": "validation_error", "message": "missing x-org header" }}3.4 503 — Service Unavailable
Section titled “3.4 503 — Service Unavailable”Used when:
- Auth unavailable
- Core unavailable (via Auth)
- access resolution fails
- dependency timeout
Example
Section titled “Example”{ "success": false, "error": { "code": "service_unavailable", "message": "unable to resolve access" }}Frontend behavior
Section titled “Frontend behavior”- show retry UI
- DO NOT assume access
4. Strict Rules
Section titled “4. Strict Rules”4.1 Never mix codes
Section titled “4.1 Never mix codes”❌ DO NOT return 403 for invalid token❌ DO NOT return 401 for missing permission❌ DO NOT return 200 with hidden failure4.2 Fail closed
Section titled “4.2 Fail closed”If access cannot be determined:
→ return 5034.3 No silent fallback
Section titled “4.3 No silent fallback”❌ DO NOT allow request if Auth fails❌ DO NOT allow request using stale cache5. Backend Mapping Table
Section titled “5. Backend Mapping Table”| Scenario | Status |
|---|---|
| Missing token | 401 |
| Invalid token | 401 |
| Expired token | 401 |
| Missing x-org | 400 |
| Invalid x-org | 400 |
| No membership | 403 |
| Module not granted | 403 |
| Permission missing | 403 |
| Delegation denied | 403 |
| Auth down | 503 |
| Core down (via Auth) | 503 |
| Cache invalid and cannot rebuild | 503 |
6. Logging Requirements
Section titled “6. Logging Requirements”Every error must log:
- userId (if available)
- companyId (if available)
- endpoint
- error code
- reason
- timestamp
7. Final Rule
Section titled “7. Final Rule”Errors must be predictable, consistent, and never ambiguous.8. One-line Summary
Section titled “8. One-line Summary”401 = who are you?403 = you cannot do this503 = system cannot decide