Error Handling
Relevant source files
The following files were used as context for generating this wiki page:
The FOSSBilling API utilizes a centralized error handling strategy designed to manage external service failures (primarily GitHub API), authentication issues, and data integrity problems. The system prioritizes graceful degradation by serving cached data when upstream dependencies are unavailable, ensuring high availability for FOSSBilling instances checking for updates or alerts.
This architecture distinguishes between different categories of failures using a specialized hierarchy of error classes, a classification utility for upstream responses, and a logging system that redacts sensitive information. The primary goal is to provide meaningful feedback to the client while preventing the exposure of internal system details or sensitive credentials.
Sources: src/lib/github-errors.ts:1-125, test/services/versions/v1/errors.test.ts:175-200, README.md:15-25
Specialized Error Hierarchy
The system defines a base GitHubError class that extends the standard JavaScript Error. This base class includes additional metadata such as HTTP status codes, internal error codes, and a priority level. Specific error types inherit from this base to categorize issues precisely.
Error Priority Levels
Errors are assigned a priority from CRITICAL to LOW. This allows the application to evaluate multiple errors and respond based on the most severe issue encountered.
| Priority | Level | Description |
|---|---|---|
| 0 | CRITICAL | Authentication failures or rate limits that halt all operations. |
| 1 | HIGH | Network timeouts or unknown system errors. |
| 2 | MEDIUM | Resource not found (404) or general GitHub errors. |
| 3 | LOW | Validation errors or malformed data. |
Sources: src/lib/github-errors.ts:1-7, test/lib/github-errors.test.ts:160-195
Error Classes
The following classes are used to represent specific failure states:
- AuthError: Triggered by 401 Unauthorized responses. Priority:
CRITICAL. - RateLimitError: Triggered by 403 Forbidden responses specifically related to API limits. Priority:
CRITICAL. - NetworkError: Triggered by request timeouts or connection failures. Priority:
HIGH. - NotFoundError: Triggered by 404 Not Found responses. Priority:
MEDIUM. - ValidationError: Triggered by invalid JSON or malformed application data. Priority:
LOW.
Sources: src/lib/github-errors.ts:22-55, test/lib/github-errors.test.ts:25-70
The diagram above shows the inheritance structure of the specialized error classes used for GitHub API interactions.
Sources: src/lib/github-errors.ts:9-55
Error Classification and Selection
The classifyGitHubError function acts as a factory, converting unknown errors or raw API responses into one of the specialized GitHubError subclasses. It performs case-insensitive string matching on error messages (e.g., checking for "rate limit", "timeout", or "json") and evaluates HTTP status codes.
When multiple operations are performed, the getMostCriticalError function iterates through a collection of errors and returns the one with the lowest numeric priority value (highest severity).
Sources: src/lib/github-errors.ts:57-125, test/lib/github-errors.test.ts:72-135
This flowchart illustrates the logic used by classifyGitHubError to transform various error inputs into categorized exceptions.
Sources: src/lib/github-errors.ts:57-113
Graceful Degradation and Caching
The API implements a "stale-while-error" pattern. If a fetch to GitHub fails, the services attempt to retrieve the last successful response from the CACHE_KV storage.
Version and Stats Service Recovery
In the Versions and Stats services, if the GitHub API is unreachable or returns an error, the system checks for cached data. If available, it returns the cached data with a stale: true flag in the response body. If no cache exists, the API returns a 503 Service Unavailable status.
Sources: src/services/stats/v1/index.ts:133-160, test/services/versions/v1/errors.test.ts:175-200, test/integration/versions/index.test.ts:192-205
Cache Corruption Handling
The system includes logic to handle corrupted cache entries. If JSON.parse fails on a KV retrieval, the error is logged, and the service proceeds to attempt a fresh fetch from the upstream source rather than crashing.
Sources: src/services/stats/v1/index.ts:148-155, test/services/versions/v1/errors.test.ts:223-245
API Response Format
A consistent response format is maintained for both successful and error states. This ensures that clients can reliably parse the status of their requests.
| Field | Type | Description |
|---|---|---|
result | mixed | The requested data, or null on failure. |
error_code | number | 0 for success, otherwise an HTTP-like status code. |
message | string | A human-readable error description or null. |
stale | boolean | Indicates if data is served from cache after a failure. |
details | object | (Optional) Contains http_status and error_code for debugging. |
Sources: test/utils/test-types.ts:10-20, src/services/stats/v1/index.ts:50-77
Logging and Sensitive Data Redaction
The internal logger (logError, logWarn, logInfo) ensures that debugging information is captured without leaking secrets. The logging utility automatically redacts sensitive keys and values from context objects before they are written to the console.
Redacted Patterns
- Keys: Any key containing
token,key,secret, orpassword(case-insensitive). - Values: Strings matching the
Bearer <token>format are partially redacted toBearer [REDACTED].
Sources: test/lib/logger.test.ts:40-165
This sequence shows how the logging middleware processes an error before outputting it to the environment logs.
Sources: test/lib/logger.test.ts:75-120
Service-Specific Error Scenarios
Different modules handle errors based on their specific requirements:
- Versions API Update: Requires a
Bearertoken. Authentication failures return401 Unauthorized. If theUPDATE_TOKENis missing from KV storage entirely, anInternal Server Error (500)is returned, but specific environment variable names are suppressed in the message to prevent information disclosure. - Central Alerts API: Database exceptions during D1 queries are caught, and a generic "Unable to load central alerts" message is returned to the client to avoid exposing the database schema.
- Stats API: If both GitHub data and the local stats cache are unavailable, it returns a
503with a specialized "Unable to fetch releases" message.
Sources: test/services/versions/v1/errors.test.ts:65-90, test/services/central-alerts/v1/index.test.ts:125-145, src/services/stats/v1/index.ts:67-77
Consistent error handling ensures the FOSSBilling API remains robust against upstream failures and secure against accidental data leaks.