Error catalog
Every error CraftBot surfaces follows a consistent envelope:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable message",
"details": [ ... ]
}
}The error.code field is generated by the global exception filter. Two paths produce it:
- Default — the filter derives
codefrom the thrown exception class name in screaming snake case.BadRequestException→BAD_REQUEST.UnauthorizedException→UNAUTHORIZED.NotFoundException→NOT_FOUND.ForbiddenException→FORBIDDEN.ConflictException→CONFLICT.UnprocessableEntityException→UNPROCESSABLE_ENTITY.InternalServerErrorException→INTERNAL_SERVER_ERROR. - Override — a service that throws with a structured payload (
new UnprocessableEntityException({ code: "DRAFT_CONFLICT", ... })) emits that explicit code instead. The filter also forwards any additional fields on the payload (e.g.blockers,warnings,currentDraft) so the client can render actionable feedback.
HTTP-class codes
These are the generic codes you will see most often. They map 1:1 to the corresponding NestJS exception classes.
| Code | HTTP status | When |
|---|---|---|
BAD_REQUEST | 400 | Malformed request — missing required field, unsupported content type. |
UNAUTHORIZED | 401 | Missing, invalid, or expired access token. |
FORBIDDEN | 403 | User has no permission for the requested action. |
NOT_FOUND | 404 | Resource id doesn’t exist or is in another tenant. |
CONFLICT | 409 | Concurrent update collision or duplicate resource. |
UNPROCESSABLE_ENTITY | 422 | Request was well-formed but business validation failed. |
THROTTLER_LIMIT_EXCEEDED | 429 | Per-client rate budget exceeded. Retry after a short delay. |
INTERNAL_SERVER_ERROR | 500 | Unhandled server failure. Reported to monitoring; safe to retry idempotent calls. |
Validation failures thrown by class-validator surface as BAD_REQUEST with details[] listing the failed fields. When a service throws an explicit VALIDATION_FAILED code (see below), the message indicates which field group failed.
Service-emitted codes
Services across the platform throw with explicit code overrides when the failure mode is specific enough to warrant a stable identifier. The current catalogue:
| Code | Where it originates |
|---|---|
CREDENTIAL_IN_USE | Cannot delete a channel credential that’s still bound to a channel config. |
CREDENTIAL_MISSING | A channel config references a credential that no longer exists. |
CREDENTIAL_NAME_EXISTS | Credential name collides with an existing record. |
DEFAULT_TRIGGER_EXISTS | A recipe already owns the default trigger for its channel. |
DRAFT_CONFLICT | Another author saved the recipe draft after your last load. Resolve via the conflict modal. |
EXPORT_TOO_LARGE | Analytics export exceeds the size cap; narrow the date range. |
FORBIDDEN_CLASS_A_REVEAL | Attempt to reveal a Class A PHI value without the required permission. |
HEALTHCARE_CONTENT_BLOCKED | Safety pre-filter matched a healthcare-restricted phrase. |
LAST_SUPER_ADMIN | Cannot remove the last super-admin. |
NOT_PUBLISHED | Operation requires a published recipe version. |
RESTORE_WINDOW_EXPIRED | Soft-deleted record is past its restoration window. |
SELF_ACTION_FORBIDDEN | User attempted to act on their own account in a forbidden way. |
SOFT_DELETED_USER | Target user is soft-deleted and must be restored first. |
SUPER_ADMIN_DELETE_FORBIDDEN | Super-admins cannot be hard-deleted. |
TEMPLATE_REQUIRES_UNRELEASED_NODES | Saving the recipe as a template requires nodes that haven’t been released. |
UNPUBLISH_FIRST | Resource must be unpublished before this operation. |
UNSUPPORTED_SCHEMA_VERSION | Recipe draft uses a schema version the API doesn’t support. |
VALIDATION_FAILED | Custom business-rule validation failure. Inspect error.details for specifics. |
WARNINGS_UNACKNOWLEDGED | Publish requires explicit acknowledgement of one or more warnings. |
Outbound HTTP failures (API node, Smart Plug runner, agent webhook) surface their network-layer code in error.details — values include ECONNABORTED, ETIMEDOUT, EAUTH, NETWORK, TIMEOUT, UNKNOWN.
When in doubt
- Check the audit log for an entry near the failure time.
- The conversation timeline shows error chips next to the message that failed.
- 5xx errors are reported to monitoring with full stack traces; 4xx errors are logged at warn level only.