From e32769ca5e5b7a5ec11981f6b7739c41938b2a5d Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Tue, 23 Dec 2025 14:36:29 -0700 Subject: [PATCH] chore(rivetkit): `RIVET_EXPOSE_ERRORS` --- .../rivetkit/src/actor/protocol/old.ts | 8 +++- .../rivetkit/src/actor/router-endpoints.ts | 12 ++++-- website/src/content/docs/actors/errors.mdx | 37 ++++++++++++++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts b/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts index e3a6aa74d9..cea51afbde 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/protocol/old.ts @@ -21,7 +21,11 @@ import { ToServerSchema, } from "@/schemas/client-protocol-zod/mod"; import { deserializeWithEncoding } from "@/serde"; -import { assertUnreachable, bufferToArrayBuffer } from "../../utils"; +import { + assertUnreachable, + bufferToArrayBuffer, + getEnvUniversal, +} from "../../utils"; import { CONN_SEND_MESSAGE_SYMBOL, type Conn } from "../conn/mod"; import { ActionContext } from "../contexts"; import type { ActorInstance } from "../instance/mod"; @@ -284,6 +288,8 @@ export async function processMessage< actionId, actionName, }, + getEnvUniversal("RIVET_EXPOSE_ERRORS") === "1" || + getEnvUniversal("NODE_ENV") === "development", ); actor.rLog.debug({ diff --git a/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts b/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts index 42185aa867..dfc9c058b5 100644 --- a/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts +++ b/rivetkit-typescript/packages/rivetkit/src/actor/router-endpoints.ts @@ -30,7 +30,7 @@ import { deserializeWithEncoding, serializeWithEncoding, } from "@/serde"; -import { bufferToArrayBuffer } from "@/utils"; +import { bufferToArrayBuffer, getEnvUniversal } from "@/utils"; import { createHttpDriver } from "./conn/drivers/http"; import { createRawRequestDriver } from "./conn/drivers/raw-request"; import type { ActorDriver } from "./driver"; @@ -198,9 +198,15 @@ export function getRequestEncoding(req: HonoRequest): Encoding { return result.data; } +/** + * Determines whether internal errors should be exposed to the client. + * Returns true if RIVET_EXPOSE_ERRORS=1 or NODE_ENV=development. + */ export function getRequestExposeInternalError(_req: Request): boolean { - // Unipmlemented - return false; + return ( + getEnvUniversal("RIVET_EXPOSE_ERRORS") === "1" || + getEnvUniversal("NODE_ENV") === "development" + ); } export function getRequestQuery(c: HonoContext): unknown { diff --git a/website/src/content/docs/actors/errors.mdx b/website/src/content/docs/actors/errors.mdx index e8b9b2d006..aacad69cf9 100644 --- a/website/src/content/docs/actors/errors.mdx +++ b/website/src/content/docs/actors/errors.mdx @@ -327,7 +327,42 @@ try { -The original error message and stack trace are logged server-side for debugging. Check your server logs to see the full error details. +### Server-Side Logging + +**All internal errors are logged server-side with full details.** When an internal error occurs, the complete error message, stack trace, and context are written to your server logs. This is where you should look first when debugging internal errors in production. + +The client receives only a generic "Internal error" message for security, but you can find the full error details in your server logs including: + +- Complete error message +- Stack trace +- Request context (actor ID, action name, connection ID, etc.) +- Timestamp + +**Always check your server logs to see the actual error details when debugging internal errors.** + +### Exposing Errors to Clients (Development Only) + +**Warning:** Only enable error exposure in development environments. In production, this will leak sensitive internal details to clients. + +For faster debugging during development, you can automatically expose internal error details to clients. This is enabled when: + +- `NODE_ENV=development` - Automatically enabled in development mode +- `RIVET_EXPOSE_ERRORS=1` - Explicitly enable error exposure + +With error exposure enabled, clients will see the full error message instead of the generic "Internal error" response: + +```typescript +// With NODE_ENV=development or RIVET_EXPOSE_ERRORS=1 +try { + await paymentActor.processPayment(100); +} catch (error) { + if (error instanceof ActorError) { + console.log(error.message); + // "Payment API returned 402: Insufficient funds" + // Instead of: "Internal error. Read the server logs for more details." + } +} +``` ## API Reference