Skip to main content

Errors

Every error response has error.code. The set is closed — if you see a code not on this list, treat it as a bug.

Codes

error.codeHTTPWhen
BAD_REQUEST400Malformed body, invalid query params, type validation failure
UNAUTHORIZED401No session, expired token, invalid bearer
PAYMENT_REQUIRED402No active subscription required by the endpoint
FORBIDDEN403Authenticated but lacking required role
NOT_FOUND404Resource doesn't exist or is hidden from caller
CONFLICT409Uniqueness violation (duplicate slug, duplicate review)
UNPROCESSABLE_ENTITY422Logical / semantic failure (e.g. release on rolling metric, invalid returnUrl)
QUOTA_EXCEEDED429Consume would exceed effective quota
INTERNAL_ERROR500Unhandled exception
SERVICE_UNAVAILABLE503Downstream dependency down (Stripe, DB transient failure)

Endpoint-specific details

CodeEndpointerror.details shape
UNAUTHORIZEDany{ signInUrl, signUpUrl }
QUOTA_EXCEEDEDPOST /me/agents/.../consume{ remaining, resetsAt, effectiveQuota }
PAYMENT_REQUIREDusage endpoints{ tierUpgradeUrl }
INVALID_RETURN_URL (subset of 422)checkout{ allowedOrigins[] }
CONFLICTreview POST{ existingReviewId }

Validation errors

class-validator is wired into the global ValidationPipe. When a body fails class-validator constraints, the response is 400 BAD_REQUEST with error.details: { errors: [{ field, constraints }] }.

Recovery hints

CodeCaller should…
401Redirect user to details.signInUrl
402Redirect user to /pricing/<agent-slug>
403Tell user they don't have permission. Don't auto-elevate.
404Treat as "not present", don't retry
409Show conflict to user, let them resolve
422Show server message to user — it's specific
429 (QUOTA_EXCEEDED)Show upgrade CTA with details.resetsAt if rolling
503Retry with backoff (max 3 attempts)

How errors are produced

In NestJS controllers/services, throwing HttpException (or a subclass like ForbiddenException) is intercepted by ErrorHandlingInterceptor, which maps to one of the codes above. Custom error codes live in src/common/errors/.

throw new HttpException(
{ code: "QUOTA_EXCEEDED", message: "...", details: { remaining: 0, ... } },
HttpStatus.TOO_MANY_REQUESTS,
);