Error Handling
Go
- Always return errors — never panic
- Wrap with context:
fmt.Errorf("userService.Create: %w", err) - Use sentinel errors for known conditions (
ErrNotFound,ErrUnauthorized) - Map domain errors to HTTP status codes in the handler layer
- Log errors with structured JSON (trace ID, operation, error message)
- Report to Sentry with trace context
TypeScript
- Use
try/catcharound Server Actions - Display user-friendly error messages via toast notifications
- Log errors with trace ID to Axiom
- Never expose internal error details to the client
API Error Response Format
{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource was not found.",
"traceId": "abc123..."
}
}Idempotency errors
| Status and code | What it means | What to do |
|---|---|---|
409 idempotency_key_reuse | The key was already used for a different method, endpoint, caller or body. | Send a new key. |
409 idempotency_in_flight | The first request with this key is still running. | Wait for Retry-After, then retry with the same key. |
400 idempotency_key_required | Access tokens only: every write needs a key. | Send an Idempotency-Key header with every write. |
A duplicate of a running write waits up to 2 seconds for the first answer and returns it.