Brain Errors
Brain converts thrown HttpException instances into the standard
JSON error envelope via HttpExceptionFilter
(apps/brain/src/common/filters/http-exception.filter.ts):
{ "statusCode": 401, "timestamp": "2026-05-05T12:00:00.000Z", "path": "/api/character/abc", "message": "Invalid token"}5xx and unexpected errors are forwarded to Sentry. All failures are logged at warn
or higher with full request context (correlation id, user id, character id, media id)
via nestjs-pino. See Observability for log routing.
HTTP errors
| Code | Trigger | Remediation | Reference |
|---|---|---|---|
401 Unauthorized — Invalid token | Clerk token verification failed (expired, signature, OAuth oat_ exchange failed). | Refresh client session; verify CLERK_SECRET_KEY matches the Clerk instance. | apps/brain/src/modules/application/auth/strategies/clerk.strategy.ts |
401 Unauthorized — No token | Missing Authorization header on a non-public route. | Caller must send Authorization: Bearer <jwt> (Clerk) or Authorization: Bearer <key> for @ApiKeyRoute(). | clerk.strategy.ts |
401 Unauthorized (api-key) | API key not in AUTHORIZED_KEYS. | Rotate or extend AUTHORIZED_KEYS; comma-separated string. | apps/brain/src/modules/application/auth/strategies/api-key.strategy.ts |
403 Forbidden — Role ‘X’ is not authorized | Clerk user resolved but lacks roles required by @Roles(...) or default ROOT, ADMIN. | Update user role in fennec via user service or sirloin admin tooling. | apps/brain/src/modules/application/auth/guards/roles.guard.ts |
400 Bad Request — Request body must include data | PUT /application-settings/:id payload missing top-level data. | Wrap payload as { "data": { ... } }. | application-settings.http.controller.ts |
400 Bad Request (Zod) | Application settings body fails Zod schema; message contains formatApplicationSettingsZodError details. | Fix payload to match the registered Zod schema for that settings key. | application-settings.http.controller.ts |
400 Bad Request (class-validator) | DTO fails class-validator rules in any controller (CustomValidationPipe). | Fix request body / query to satisfy DTO; message is an array of validator errors. | apps/brain/src/common/pipes/pipes/custom-validation.pipe.ts |
404 Not Found | Resource lookups (character, media, generation, tag) returning empty. | Verify resource id; confirm caller is querying the right environment. | Multiple controllers, generally raised from services. |
409 Conflict | Unique-constraint violations surfaced from Prisma. | Inspect logged err.meta.target; resolve duplicate before retry. | Various services; underlying Prisma error code P2002. |
501 Not Implemented — Endpoint deprecated | POST /api/webhook/rp/training is intentionally retired. | Stop calling it; RunPod training webhook flow is gone. | webhook.http.controller.ts |
500 Internal Server Error (HttpExceptionFilter fallback) | Any non-HttpException thrown bubbles up. | Triage in Sentry / Axiom by correlation_id; reproduce via repro endpoint. | http-exception.filter.ts |
Round client errors
Round-side failures are wrapped at apps/brain/src/modules/application/round/errors/:
| Class | Trigger | Remediation |
|---|---|---|
RoundServiceUnavailableException | gRPC connection failure / health check fail. | Confirm ROUND_HOST; check round Railway service status. |
RoundServiceTimeoutException | Call exceeded the configured deadline. | Re-tune timeout; check round CPU/GPU pressure. |
RoundServiceInvalidResponseException | Round returned an unexpected proto shape. | Regenerate stubs; verify proto compatibility (make generate-proto). |
RoundServiceException (base) | Generic gRPC error. | Inspect inner cause. |
A circuit breaker in apps/brain/src/modules/application/round/interceptors/circuit-breaker.interceptor.ts short-circuits round calls after sustained failure — expect RoundServiceUnavailableException while open.
Generation pipeline errors
| Class | Trigger | Remediation |
|---|---|---|
ContentModerationException | Hive or internal moderation flagged the input. Logged at warn, not Sentry-paged. | Check moderation logs; user-facing message must not leak internal details. |
| Provider exceptions (FAL / RunPod / Wavespeed / Kling / Vertex) | 4xx/5xx from upstream provider. | Inspect provider logs; check API key validity and quota. |
| BullMQ stalled jobs | Worker crash mid-job; emitted via OnWorkerEvent('stalled') in MediaFlowsProcessor. | Inspect Bull Board (/queues); check Redis connection; resume via the dashboard. |
Prisma errors
Prisma errors propagate as unknown/Error subtypes; the filter logs them at error and Sentry pages on 5xx.
| Prisma code | Trigger | Remediation |
|---|---|---|
P2002 | Unique-constraint violation. | Map to 409 Conflict in service; surface offending field. |
P2003 | Foreign-key constraint failed. | Validate referenced id exists. |
P2025 | Record not found on update/delete. | Map to 404 Not Found. |
P1001 | Cannot reach database. | Check DATABASE_URL, network, Neon status. |
P1017 | Server closed connection. | Common with pooler; usually transient. |
Clerk errors
@clerk/backend wraps issues from Clerk Frontend API:
| Symptom | Trigger | Remediation |
|---|---|---|
oat_ token rejected | OAuth opaque token; Clerk Frontend API /oauth/userinfo exchange failed. | Verify CLERK_FRONTEND_API_URL reachable; check Clerk instance domain. |
| Session JWT rejected | Wrong CLERK_SECRET_KEY for issuer. | Match secret to the Clerk instance issuing the token. |
| Network timeout | Clerk API outage. | Check Clerk status page; Brain has no offline session cache. |
BullMQ errors
| Symptom | Trigger | Remediation |
|---|---|---|
| Jobs not draining | Redis unreachable or auth wrong. | Check REDIS_HOST/PORT/PASSWORD and Railway Redis service. |
Jobs marked failed with MaxStalledCount | Worker repeatedly crashed. | Investigate via Bull Board; restart workers; inspect Sentry for crash stack. |
| Memory growth | Backlog of completed/failed jobs above retention. | removeOnComplete / removeOnFail is set in queue.config.ts; raise retention only if needed. |
TODO
- No controller maps Prisma
P2002/P2025to dedicatedConflictException/NotFoundException; unmapped Prisma errors propagate to the global filter as 500 (noPrismaClientKnownRequestErrorreferences inapps/brain/src/). ContentModerationExceptionis the sole moderation error subclass underapps/brain/src/modules/domain/generation/errors/; no other moderation subclasses exist (sibling exceptions:application-misconfigured,entity-not-found,entity-unable-to-process).- Round circuit-breaker defaults (
apps/brain/src/modules/application/round/interceptors/circuit-breaker.interceptor.ts:37-43):errorThresholdPercentage: 50,volumeThreshold: 10,rollingCountTimeout: 10000ms(10 buckets × 1s),resetTimeout: 15000ms(half-open probe), per-calltimeout: 35000ms.