Error Handling
Handle API errors with typed error classes, automatic retries, and structured error responses.
Error Response Format
All API errors return a JSON object with a consistent structure:
{
"error": "not_found",
"message": "No NDC found for code 0000-0000-00",
"code": "NDC_NOT_FOUND"
}
| Field | Type | Description |
|---|---|---|
error |
string | Machine-readable error type (e.g., "validation_error", "not_found") |
message |
string | Human-readable description of what went wrong |
code |
string? | Optional error code for specific error conditions |
HTTP Status Codes
| Status | Error Type | When It Happens |
|---|---|---|
400 |
ValidationError |
Invalid input — missing required parameters, bad format |
401 |
AuthenticationError |
Missing or invalid API key / OAuth token |
403 |
ForbiddenError |
Valid credentials but insufficient scopes |
404 |
NotFoundError |
The requested resource does not exist |
429 |
RateLimitError |
Per-second rate limit exceeded |
429 |
QuotaExceededError |
Monthly quota exhausted |
500 |
ServerError |
Internal server error |
502 |
ServerError |
Bad gateway |
503 |
ServerError |
Service temporarily unavailable |
SDK Typed Errors
The @fhirfly-io/terminology SDK maps every API error to a typed error class. This lets you handle specific error conditions without parsing status codes or response bodies.
Node.js
import {
Fhirfly,
NotFoundError,
RateLimitError,
ValidationError,
AuthenticationError,
QuotaExceededError,
} from "@fhirfly-io/terminology";
const client = new Fhirfly({ apiKey: "your-api-key" });
try {
const ndc = await client.ndc.lookup("0000-0000-00");
} catch (err) {
if (err instanceof NotFoundError) {
// The code doesn't exist
console.log(`Not found: ${err.code_type} ${err.code_value}`);
} else if (err instanceof RateLimitError) {
// Rate limited — SDK will auto-retry, but you can inspect details
console.log(`Rate limited. Retry after: ${err.retryAfter}s`);
} else if (err instanceof QuotaExceededError) {
// Monthly quota exhausted — no auto-retry
console.log(`Quota used: ${err.quotaUsed} / ${err.quotaLimit}`);
} else if (err instanceof ValidationError) {
// Bad input
console.log(`Invalid input: ${err.message} (field: ${err.field})`);
} else if (err instanceof AuthenticationError) {
// Bad credentials
console.log("Check your API key");
} else {
throw err; // Unexpected error
}
}
Error Class Reference
| Class | Status | Key Properties |
|---|---|---|
ApiError |
any | statusCode, code, details — base class for all API errors |
AuthenticationError |
401 | Extends ApiError |
ValidationError |
400 | field — the input field that failed validation |
NotFoundError |
404 | code_type, code_value — what was looked up |
RateLimitError |
429 | retryAfter, limit, remaining, reset |
QuotaExceededError |
429 | quotaLimit, quotaUsed, quotaResetDate |
ServerError |
5xx | Extends ApiError |
NetworkError |
— | cause — the underlying network error |
TimeoutError |
— | timeoutMs — the timeout threshold that was exceeded |
All typed error classes extend FhirflyError, which extends the standard Error class.
Retry Behavior
The SDK includes built-in retry logic with exponential backoff for transient errors:
| Error Type | Auto-Retry | Notes |
|---|---|---|
RateLimitError (429) |
Yes | Respects Retry-After header |
ServerError (5xx) |
Yes | Up to 3 retries with exponential backoff |
NetworkError |
Yes | Connection failures, DNS errors |
TimeoutError |
Yes | Request timeouts |
ValidationError (400) |
No | Bad input — fix the request |
AuthenticationError (401) |
No | Bad credentials — fix the key |
NotFoundError (404) |
No | Resource doesn't exist |
QuotaExceededError (429) |
No | Monthly quota exhausted |
Configuring Retries
Node.js
const client = new Fhirfly({
apiKey: "your-api-key",
maxRetries: 5, // Default: 3
timeout: 30_000, // Default: 10_000 (10 seconds)
});
Set maxRetries: 0 to disable automatic retries entirely.
Network Errors
NetworkError and TimeoutError are thrown when the SDK cannot reach the API server. These are not HTTP errors — they occur before any response is received.
Node.js
import { Fhirfly, NetworkError, TimeoutError } from "@fhirfly-io/terminology";
try {
const result = await client.ndc.lookup("0069-0151-01");
} catch (err) {
if (err instanceof TimeoutError) {
console.log(`Request timed out after ${err.timeoutMs}ms`);
} else if (err instanceof NetworkError) {
console.log(`Network error: ${err.message}`);
console.log(`Cause: ${err.cause?.message}`);
}
}
See Also
- Rate Limits — Rate limit details and quota management
- Authentication — API key and OAuth2 setup
- Scopes — Scope requirements per endpoint