Skip to content

Commit e899a92

Browse files
authored
Tunnel debug port RPC errors to callers (#6507)
The debug port's getEntrypoint() and getActor() methods used plain KJ_ASSERT_NONNULL for error cases (service not found, entrypoint not found, DO class not found). KJ exceptions without a jsg. prefix get sanitized by decodeTunneledException() into a generic "internal error; reference = <id>" before reaching the caller. Prefix these assertion messages with "jsg.Error:" so they tunnel through capnp RPC and the caller receives the actual error description (e.g. "Entrypoint not found: NonExistentEntrypoint").
1 parent 271477b commit e899a92

2 files changed

Lines changed: 12 additions & 11 deletions

File tree

src/workerd/server/server-test.c++

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5952,7 +5952,7 @@ KJ_TEST("Server: debug port RPC calls") {
59525952
};
59535953

59545954
// Test 1: Request a non-existent service should fail
5955-
KJ_EXPECT_THROW_MESSAGE("Service not found",
5955+
KJ_EXPECT_THROW_MESSAGE("Worker \"nonexistent\" not found",
59565956
getBootstrap("nonexistent", kj::none, [](auto& props) { props.setEmptyObject(); }));
59575957

59585958
// Test 2: Get entrypoint for different services

src/workerd/server/server.c++

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5507,9 +5507,9 @@ class Server::DebugPortListener {
55075507
auto serviceName = params.getService();
55085508
auto propsReader = params.getProps();
55095509

5510-
// Look up the service
5511-
auto& serviceEntry =
5512-
KJ_ASSERT_NONNULL(srv.services.find(serviceName), "Service not found", serviceName);
5510+
// Look up the service.
5511+
auto& serviceEntry = KJ_ASSERT_NONNULL(srv.services.find(serviceName),
5512+
kj::str("jsg.Error: Worker \"", serviceName, "\" not found"));
55135513
auto service = serviceEntry->service();
55145514

55155515
// Convert props from Frankenvalue if provided
@@ -5531,11 +5531,11 @@ class Server::DebugPortListener {
55315531

55325532
targetService =
55335533
KJ_ASSERT_NONNULL(workerService->getEntrypoint(maybeEntrypoint, kj::mv(props)),
5534-
"Entrypoint not found", maybeEntrypoint.orDefault("(default)"));
5534+
kj::str("jsg.Error: Worker does not export an entrypoint named \"",
5535+
maybeEntrypoint.orDefault("(default)"), "\""));
55355536
} else {
55365537
// Not a WorkerService
5537-
KJ_ASSERT(
5538-
!params.hasEntrypoint(), "Service does not support named entrypoints", serviceName);
5538+
KJ_ASSERT(!params.hasEntrypoint(), "jsg.Error: Worker does not support named entrypoints");
55395539

55405540
// Try to apply props if the service supports it
55415541
if (params.hasProps()) {
@@ -5560,17 +5560,18 @@ class Server::DebugPortListener {
55605560
auto actorIdStr = params.getActorId();
55615561

55625562
// Look up the service
5563-
auto& serviceEntry =
5564-
KJ_ASSERT_NONNULL(srv.services.find(serviceName), "Service not found", serviceName);
5563+
auto& serviceEntry = KJ_ASSERT_NONNULL(srv.services.find(serviceName),
5564+
kj::str("jsg.Error: Worker \"", serviceName, "\" not found"));
55655565
auto service = serviceEntry->service();
55665566

55675567
// Try to cast to WorkerService
55685568
auto* workerService = dynamic_cast<WorkerService*>(service);
5569-
KJ_REQUIRE(workerService != nullptr, "Service does not support actors", serviceName);
5569+
KJ_REQUIRE(workerService != nullptr, "jsg.Error: Worker does not support Durable Objects");
55705570

55715571
// Look up the actor namespace
55725572
auto& actorNamespace = KJ_ASSERT_NONNULL(workerService->getActorNamespace(entrypointName),
5573-
"Actor namespace not found", entrypointName);
5573+
kj::str("jsg.Error: Worker does not export a Durable Object class named \"",
5574+
entrypointName, "\""));
55745575

55755576
// Create an actor ID - use the namespace config to determine if it's durable or ephemeral
55765577
Worker::Actor::Id actorId;

0 commit comments

Comments
 (0)