Error Handling
Solvix provides structured error handling. Every failed request throws an Error with context about what went wrong.
Error Types
HTTP Errors
By default, any response with status outside 200–299 throws an error:
try {
await client.get("/nonexistent");
} catch (error) {
console.error(error.message);
// "Request failed with status 404"
}Customize with validateStatus:
const client = createClient({
validateStatus: (status) => status < 500,
});
// 404 won't throw; 502 will
await client.get("/missing"); // no errorTimeout Errors
When a request exceeds the configured timeout:
const client = createClient({ timeout: 1000 });
try {
await client.get("/slow-endpoint");
} catch (error) {
console.error(error.message);
// "The operation was aborted" (AbortError)
}Network Errors
DNS failures, connection refused, or fetch-level errors:
try {
await client.get("https://nonexistent-domain.xyz");
} catch (error) {
console.error(error.message);
// "fetch failed" / "getaddrinfo ENOTFOUND"
}Circuit Breaker Rejects
When the circuit is open, requests fail immediately:
const client = createClient({
circuitBreaker: { failureThreshold: 3, resetTimeout: 10000 },
});
try {
await client.get("/failing-api");
} catch (error) {
console.error(error.message);
// "Circuit breaker is open"
}Validation Errors
When validateResponse throws (e.g., Zod parse failure):
const client = createClient({
validateResponse: (data) => {
if (!data.id) throw new Error("Missing id field");
return data;
},
});
try {
await client.get("/malformed");
} catch (error) {
console.error(error.message);
// "Missing id field"
}Rate Limit Errors
When rate limit capacity is exhausted:
try {
await client.get("/rate-limited");
} catch (error) {
console.error(error.message);
// "Rate limit exceeded"
}Error Context via Error Events
Subscribe to SolvixBus for structured error data:
import { SolvixBus } from "@adityadev13/solvix";
SolvixBus.on("request:error", (event) => {
const { context, timestamp } = event;
console.error({
url: context.url,
error: context.error,
attempt: context.meta.attemptNumber,
duration: context.meta.duration,
correlationId: context.meta.correlationId,
});
});Error Handling with Hooks
Handle errors globally with hooks:
const client = createClient({
hooks: {
onError: (error, ctx) => {
console.error(`[${ctx.meta.correlationId}] ${ctx.url}: ${error}`);
// Send to Sentry, Datadog, etc.
},
},
});Retry and Error Interaction
When retries are enabled, the error is only thrown after all retries are exhausted:
const client = createClient({
retry: { retries: 3 },
});
try {
await client.get("/flaky");
} catch (error) {
// All 3 retries failed — this is the final error
console.log(`Failed after attempts`);
}Check ctx.meta.retryCount in error events to see how many retries were attempted.
Best Practices
- Use
SolvixBusfor global error monitoring — centralize error handling instead of try/catch on every request - Set
onErrorhooks for integrating with Sentry, Datadog, etc. - Combine with
fallbackURLs— specify backup endpoints that are tried when the primary fails validateStatusfor non-standard APIs — some APIs return 200 with error bodies; handle them withtransformResponse- Enable
devModeduring development to get warnings about common misconfigurations
const client = createClient({
devMode: true, // warns about common mistakes
fallbackURLs: ["https://backup.example.com/api"],
});What's Next
- Status Validation — customize which status codes are errors
- Fallback URLs — automatic failover to backup endpoints
- Logging & Events — global event bus for error monitoring