Skip to content

feat: forward target URL as the 4th argument in error events#135

Open
bjohansebas wants to merge 1 commit into
unjs:mainfrom
bjohansebas:url
Open

feat: forward target URL as the 4th argument in error events#135
bjohansebas wants to merge 1 commit into
unjs:mainfrom
bjohansebas:url

Conversation

@bjohansebas
Copy link
Copy Markdown

@bjohansebas bjohansebas commented May 11, 2026

The error event listener on a ProxyServer only receives (err, req, res), the 4th argument (the target URL the proxy was trying to reach) is always undefined

error: [err: Error, req?: Req, res?: Res | net.Socket, target?: URL | ProxyTarget];
.

This breaks consumers that rely on it for logging or error handling. The most visible case is http-proxy-middleware@4, whose default loggerPlugin produces messages like:

[HPM] Error occurred while proxying request 127.0.0.1:51234/my-path to undefined [ENOTFOUND] …

instead of showing the actual target (http://unknown:1234/).

This matches the original http-proxy@1.18.1 behaviour:

his helps resolve webpack-dev-server being able to update http-proxy-middleware, which now uses this package webpack/webpack-dev-server#5663

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced error event handling to include the proxied target URL as an additional parameter, providing more context when errors are emitted.
  • Tests

    • Added test coverage for error event handling with target URL parameter.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

📝 Walkthrough

Walkthrough

The PR enhances the proxy's error event emission to include the proxied target URL as a 4th argument, enabling error listeners to identify which upstream target caused the failure. The implementation updates the middleware error callback signature and the server error emission path, with tests verifying the behavior in both direct proxy errors and middleware exception scenarios.

Changes

Error Event Target URL Enhancement

Layer / File(s) Summary
Proxy Error Handler Implementation
src/server.ts
The _createProxyFn middleware error callback now receives a URL parameter and emits the error event with requestOptions.target as the 4th argument. Promise behavior is preserved: rejected when no listeners exist, resolved after emission when listeners are present.
Error Event Tests
test/http-proxy.test.ts, test/index.test.ts
Two test cases verify the error event includes the target URL as the 4th argument: one from direct proxy errors and one from middleware exceptions. Both assert the URL is a URL instance matching the configured target.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • unjs/httpxy#102: Both PRs modify the proxy error-emission path to include the proxied target/URL as an additional (4th) argument when emitting "error" (i.e., they change the error handler signature).

Suggested reviewers

  • pi0
  • sapphi-red

Poem

🐰 A bunny hops through error streams,
With target URLs, or so it seems,
The fourth argument holds the key—
Which upstream caused the fault we see!
Listeners rejoice, no more the dark,
Now errors glow with purpose's spark.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: forwarding the target URL as the 4th argument in error events, which is the primary objective of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/server.ts (1)

225-245: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Middleware error callbacks must pass the URL as the 4th argument on all code paths.

The callback on line 138 correctly passes all 4 arguments: callback(err, req, res, url). However, the socket error handlers at lines 160 and 169 invoke the callback with only 3 arguments: callback(err, req, socket). Since the callback signature has url? as optional, those invocations will receive undefined for the url parameter, which will cause url to be undefined when the error event is emitted (line 240 in server.ts). Either pass the url/target to the callback on all paths, or reconsider the error handling flow for socket-level errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.ts` around lines 225 - 245, The middleware error callback passed
into server._getPasses(type) must always be invoked with four arguments (error,
req, resOrSocket, url); update the socket-level error handlers that currently
call callback(err, req, socket) to pass the url/target as the fourth parameter
(e.g., the same url/target used when invoking pass or requestOptions.target) so
that the downstream logic that checks server.listenerCount("error") and calls
server.emit("error", error, req, res, url) always receives a defined url; ensure
all code paths that call the callback (including socket error handlers) use the
same callback signature.
🧹 Nitpick comments (1)
test/index.test.ts (1)

185-253: 💤 Low value

Recommended: extract shared setup helper for the two middleware pass exceptions tests.

The target-server and proxy-server scaffolding (lines 186‑230) is a near-verbatim copy of the test at lines 112‑158. A small helper would shrink the file and reduce drift between the two cases. Non-blocking — the assertions and finally-block cleanup are correct as-is.

♻️ Sketch of a shared helper
async function setupProxy(throwing: () => never) {
  const target = await listen((_req, res) => res.end("ok")); // reuse `listen` from top of file
  const proxy = createProxyServer({ target: target.url });
  proxy.before("web", "", throwing);
  const proxyServer = await listen((req, res) => {
    void proxy.web(req, res);
  });
  return { target, proxy, proxyServer };
}

Each test then becomes setup + the unique assertion + finally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/index.test.ts` around lines 185 - 253, The test duplicates server/proxy
setup in two places; extract a shared helper (e.g., setupProxy or reuse the
existing listen helper) that creates the target HTTP server (res.end("ok")),
calls createProxyServer({ target: target.url }), registers the before("web",
...) handler via proxy.before, and starts the proxyServer that calls proxy.web
for incoming requests, returning { target, proxy, proxyServer } so both tests
can call the helper and keep their unique assertions and cleanup in the finally
block; locate references to createProxyServer, proxy.before, proxy.web and the
current target/proxy/proxyServer variables to implement this refactor.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/server.ts`:
- Around line 225-245: The middleware error callback passed into
server._getPasses(type) must always be invoked with four arguments (error, req,
resOrSocket, url); update the socket-level error handlers that currently call
callback(err, req, socket) to pass the url/target as the fourth parameter (e.g.,
the same url/target used when invoking pass or requestOptions.target) so that
the downstream logic that checks server.listenerCount("error") and calls
server.emit("error", error, req, res, url) always receives a defined url; ensure
all code paths that call the callback (including socket error handlers) use the
same callback signature.

---

Nitpick comments:
In `@test/index.test.ts`:
- Around line 185-253: The test duplicates server/proxy setup in two places;
extract a shared helper (e.g., setupProxy or reuse the existing listen helper)
that creates the target HTTP server (res.end("ok")), calls createProxyServer({
target: target.url }), registers the before("web", ...) handler via
proxy.before, and starts the proxyServer that calls proxy.web for incoming
requests, returning { target, proxy, proxyServer } so both tests can call the
helper and keep their unique assertions and cleanup in the finally block; locate
references to createProxyServer, proxy.before, proxy.web and the current
target/proxy/proxyServer variables to implement this refactor.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83e08256-7de1-4caf-bf18-4e8796faefb9

📥 Commits

Reviewing files that changed from the base of the PR and between 9dc2425 and 1f3f726.

📒 Files selected for processing (3)
  • src/server.ts
  • test/http-proxy.test.ts
  • test/index.test.ts

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.

1 participant