autotel-structured-errors
corecreateStructuredError, parseError, recordStructuredError. API errors with message, why, fix, link; client parsing for UI. Use in API routes and client catch blocks.
Autotel — Structured Errors
Throw errors with createStructuredError({ message, why?, fix?, link?, status?, cause? }) in API routes and services. On the client, use parseError(caught) to get message, status, why, fix, link for toasts and UI.
Setup
Server (API route or service):
import { createStructuredError } from 'autotel';
if (!user) {
throw createStructuredError({
message: 'User not found',
status: 404,
why: `No user with ID "${userId}"`,
fix: 'Check the user ID and try again',
link: 'https://docs.example.com/errors/user-not-found',
});
}
Client:
import { parseError } from 'autotel';
try {
await fetch('/api/checkout', { method: 'POST', body: JSON.stringify(data) });
} catch (err) {
const e = parseError(err);
toast.error(e.message, { description: e.why });
if (e.fix) setHelp(e.fix);
if (e.link) setDocLink(e.link);
}
Core Patterns
Wrap a caught error (preserve cause):
try {
await stripe.charges.create(data);
} catch (err) {
throw createStructuredError({
message: 'Payment failed',
status: 402,
why: err instanceof Error ? err.message : 'Unknown error',
fix: 'Try a different payment method or contact support',
link: 'https://docs.stripe.com/declines',
cause: err,
});
}
Record on current span: Use recordStructuredError(ctx, error) or the request logger's .error(error, fields) so the span gets error attributes and status.
parseError handles FetchError (ofetch), nested data.data, and plain Error. Returns { message, status, why?, fix?, link?, raw }.
Common Mistakes
HIGH Throw new Error() in API routes instead of createStructuredError
Wrong:
throw new Error('Payment failed');
Correct:
throw createStructuredError({
message: 'Payment failed',
status: 402,
why: 'Card declined by issuer',
fix: 'Try a different payment method',
link: 'https://docs.example.com/payments',
});
Clients and agents need structured fields (why, fix, link) for actionable errors. parseError() reads these from API responses.
Source: docs/AGENT-GUIDE.md, AGENTS.md
MEDIUM Client only shows error.message and ignores why/fix/link
Wrong:
catch (err) {
toast.error(err.message);
}
Correct:
import { parseError } from 'autotel';
catch (err) {
const e = parseError(err);
toast.error(e.message, { description: e.why });
if (e.fix) showFix(e.fix);
if (e.link) setDocLink(e.link);
}
parseError() extracts status, why, fix, and link from API error responses and FetchError so the UI can show them.
Source: docs/AGENT-GUIDE.md
Version
Targets autotel v2.23.x.
See also: autotel-request-logging/SKILL.md — use .error() to record errors in the request snapshot.