Skip to content

Tunnel debug port RPC errors to callers#6507

Merged
penalosa merged 8 commits intomainfrom
penalosa/debug-port-error-messages
Apr 14, 2026
Merged

Tunnel debug port RPC errors to callers#6507
penalosa merged 8 commits intomainfrom
penalosa/debug-port-error-messages

Conversation

@penalosa
Copy link
Copy Markdown
Contributor

@penalosa penalosa commented Apr 7, 2026

Summary

  • Prefix debug port getEntrypoint() and getActor() assertion messages with jsg.Error: so they tunnel through capnp RPC instead of being sanitized to generic internal error; reference = <id> messages.

Background

The debug port is used by the dev registry to proxy service bindings and Durable Object bindings across wrangler dev / vite dev processes. When a caller references a non-existent entrypoint or DO class, the KJ assertions in the debug port handler produce descriptive errors (e.g. "Entrypoint not found"), but decodeTunneledException() treats them as internal errors and replaces the message with an opaque reference ID.

The jsg.Error: prefix marks these as user-facing errors that should be forwarded as-is, matching the pattern used elsewhere in the codebase (e.g. JSG_REQUIRE_NONNULL).

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

The generated output of @cloudflare/workers-types matches the snapshot in types/generated-snapshot 🎉

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm Bonk, and I've done a quick review of your PR.

This PR prefixes debug port assertion messages with jsg.Error: so they tunnel through capnp RPC. The tunneling mechanism itself works correctly — tunneledErrorType() will recognize the prefix and mark these as non-internal errors.

However, there's one issue that affects all the changed assertions:

  1. [MEDIUM] KJ assertion formatting artifacts leak into user-visible error messages. When KJ assertion macros have multiple arguments, extra args are formatted as ; varName = value with the variable name as a label. This means users will see messages like Service not found:; serviceName = myService instead of Service not found: myService. The JSG_REQUIRE/JSG_REQUIRE_NONNULL macros avoid this by pre-formatting with kj::str() — the same approach should be used here.

This review was generated by an AI assistant and may contain inaccuracies.

Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Apr 7, 2026

The review has been posted on PR #6507. Here's a summary of the finding:

[MEDIUM] KJ assertion formatting artifacts leak into user-visible error messages. The PR correctly uses the jsg.Error: prefix for tunneling, but passes extra arguments (like serviceName) as separate KJ assertion macro arguments. KJ formats these with ; varName = value labels, so users would see error messages like Service not found:; serviceName = myService instead of the cleaner Service not found: myService. The fix is to wrap the message with kj::str() to pre-format it into a single string, matching how JSG_REQUIRE_NONNULL handles this internally. I posted concrete suggestion comments on all 6 affected assertion sites.

github run

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 9, 2026

Merging this PR will not alter performance

✅ 72 untouched benchmarks
⏩ 129 skipped benchmarks1


Comparing penalosa/debug-port-error-messages (b3f6921) with main (271477b)

Open in CodSpeed

Footnotes

  1. 129 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@penalosa penalosa force-pushed the penalosa/debug-port-error-messages branch from 13cab4a to 77be143 Compare April 13, 2026 12:46
@penalosa penalosa marked this pull request as ready for review April 13, 2026 18:34
@penalosa penalosa requested review from a team as code owners April 13, 2026 18:34
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
@penalosa penalosa force-pushed the penalosa/debug-port-error-messages branch from b4ad6fe to 88909c0 Compare April 13, 2026 22:22
Copy link
Copy Markdown
Collaborator

@danlapid danlapid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to clean up commits before merging

@penalosa penalosa enabled auto-merge (squash) April 13, 2026 22:30
@penalosa penalosa force-pushed the penalosa/debug-port-error-messages branch from 88909c0 to efdb69b Compare April 14, 2026 01:35
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").
The nonexistent-service test triggers a capnp RPC ERROR log that cannot
be captured by KJ_EXPECT_LOG (the RPC layer logs through the event loop's
ExceptionCallback chain, not the test's). Remove the negative test case;
the positive cases (entrypoints, props, actors, JS RPC) still provide
good coverage of the debug port RPC path.
Return a kj::Exception directly instead of throwing via KJ_ASSERT_NONNULL
in getEntrypoint(). Throwing synchronously causes capnp RPC to log the
error through an ExceptionCallback chain that KJ_EXPECT_LOG cannot
intercept in tests. Returning a rejected promise avoids this while still
delivering the same error to the caller.
…str()

Revert the KJ_IF_SOME + return pattern — KJ_ASSERT_NONNULL with kj::str()
works fine. The original test failure was a message mismatch, not a
kj::str() issue.

Remove kj::str() wrapping where there's no interpolation, per review.
@penalosa penalosa force-pushed the penalosa/debug-port-error-messages branch from efdb69b to b3f6921 Compare April 14, 2026 12:46
@penalosa penalosa merged commit e899a92 into main Apr 14, 2026
22 checks passed
@penalosa penalosa deleted the penalosa/debug-port-error-messages branch April 14, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants