Error Handling
LogStitch uses consistent error responses across all endpoints. Every error includes a machine-readable code and a human-readable message.
Error Response Format#
All error responses follow the same JSON structure. The error.code field is a stable, machine-readable string you can match against in your code. The error.details array provides additional context for validation errors.
{
"error": {
"code": "validation_error",
"message": "Invalid event data",
"details": [
{
"field": "action",
"message": "Action must be dot-namespaced (e.g. user.created)"
}
]
},
"request_id": "req_abc123"
}Error Codes#
The following error codes can be returned by the LogStitch API.
| Code | HTTP Status | Description |
|---|---|---|
| validation_error | 400 | Request failed Zod validation |
| unauthorized | 401 | Missing or invalid API key / viewer token |
| forbidden | 403 | Key type lacks permission for this action |
| not_found | 404 | Resource does not exist |
| conflict | 409 | Resource conflict |
| rate_limited | 429 | Too many requests |
| daily_event_limit_reached | 429 | Free tier daily limit of 1,000 events exceeded |
| key_revoked | 401 | API key has been revoked |
| invalid_api_key | 401 | API key format invalid or not recognized |
| alert_rule_limit_reached | 403 | Custom alert rule limit reached for your plan |
| webhooks_not_available | 403 | Webhook delivery requires a paid plan |
| stream_not_found | 404 | Stream does not exist for the given claim token |
| stream_expired | 410 | Stream has expired (unclaimed for 7 days) |
| stream_already_claimed | 410 | Stream has already been claimed by a project |
| stream_daily_limit_reached | 429 | Stream daily limit of 100 events exceeded |
| internal_error | 500 | Unexpected server error |
SDK Error Handling#
The LogStitch SDK provides two modes for handling errors. Choose the one that fits your use case.
Fire-and-Forget (Default)#
By default, the SDK silently swallows errors so audit logging never disrupts your application. Use the onError callback to observe failures without throwing.
import { LogStitch } from '@logstitch/sdk';
const logstitch = new LogStitch({
projectKey: 'pk_...',
onError: (error) => {
// Log to your observability platform
console.error('LogStitch error:', error.code, error.message);
},
});
// This will never throw, even if the request fails
await logstitch.log({
action: 'user.signed_in',
category: 'auth',
actor: { id: 'user_123', type: 'user' },
tenant_id: 'acme_corp',
});Strict Mode#
Enable strict mode when audit logging is critical and you want failures to surface immediately. Errors throw a LogStitchError that you can catch and handle.
import { LogStitch, LogStitchError } from '@logstitch/sdk';
const logstitch = new LogStitch({
projectKey: 'pk_...',
strict: true,
});
try {
await logstitch.log({
action: 'payment.processed',
category: 'mutation',
actor: { id: 'user_456', type: 'user' },
tenant_id: 'acme_corp',
});
} catch (error) {
if (error instanceof LogStitchError) {
console.error(error.code); // "daily_event_limit_reached"
console.error(error.status); // 429
console.error(error.requestId); // "req_abc123"
}
}LogStitchError#
The LogStitchError class extends Error with additional properties from the API response.
interface LogStitchError extends Error {
message: string; // Human-readable error message
status: number; // HTTP status code (e.g. 401, 429)
code: string; // Machine-readable error code (e.g. "unauthorized")
requestId: string; // Unique request ID for debugging
}Rate Limits#
The free tier allows 1,000 events per day per project with 7-day retention. When the daily limit is exceeded, the API returns HTTP 429 with the error code daily_event_limit_reached.
{
"error": {
"code": "daily_event_limit_reached",
"message": "Daily event limit of 1000 reached. Upgrade to increase your limit.",
"details": []
},
"request_id": "req_01JKQ..."
}SDK does not retry 4xx errors
LogStitchError in strict mode.Request IDs#
Every API response includes a request_id field. This is a unique identifier for the request that can be used for debugging and tracing. When contacting support, always include the request ID for faster resolution.
try {
await logstitch.log(event);
} catch (error) {
if (error instanceof LogStitchError) {
// Include this in support tickets
console.error('Request ID:', error.requestId);
}
}