Skip to content

docs: clarify that origin is optional only for origin-bound dispatchers - #5994

Merged
mcollina merged 1 commit into
nodejs:mainfrom
attilayener:docs/clarify-optional-origin
Oct 19, 2026
Merged

mcollina merged 1 commit into
nodejs:mainfrom
attilayener:docs/clarify-optional-origin

Conversation

@attilayener

Copy link
Copy Markdown
Contributor

Summary

Dispatcher.md documented the origin option of dispatcher.dispatch() as "(optional)", which reads as "never required". That is only true for a dispatcher already bound to a single origin. Agent is not bound to one origin and requires it, so the docs contradicted the runtime.

This also answers the question #1011 asked in 2021: are we allowed to specify origin and path in the options object passed as the second argument to request and friends? Why or why not?

Verified against current main

I ran each case rather than reasoning from the types:

new Pool(origin).request({ path, method })     // -> 200
new Client(origin).request({ path, method })    // -> 200
new Agent().request({ path, method })           // -> InvalidArgumentError
                                               //    'opts.origin must be a non-empty string or URL.'
new Agent().request({ origin, path, method })  // -> 200

The two paths differ because Client/Pool fill the origin from this[kUrl].origin when kDispatch builds the Request, while Agent rejects a missing origin in its own dispatch:

  • lib/dispatcher/client.js — new Request(this[kUrl].origin, opts, handler)
  • lib/dispatcher/agent.js — throws InvalidArgumentError

Consistency check

docs/docs/api/Agent.md already documents origin as "Required." for Agent.dispatch(), and Client.md notes origin "is omitted because the client is bound to a single origin". This change aligns the abstract Dispatcher docs with both, rather than asserting a rule that the concrete subclasses break.

path, by contrast, is documented as required and that is correct — lib/core/request.js throws path must be a string, so I left it alone.

Test coverage

test/node-test/dispatcher-optional-origin.js pins the distinction, which previously had no coverage.

Validation

Run against Node v24.21.0:

node --test test/node-test/dispatcher-optional-origin.js    4/4 pass
node --test test/node-test/agent.js                         35/35 pass
node --test test/node-test/balanced-pool.js                 25/25 pass
eslint test/node-test/dispatcher-optional-origin.js          clean

test/ and lib/ are otherwise untouched — the diff is one docs file plus one new test file.

Mutation check

Because a passing test is not the same as a protective test, I checked these tests actually fail when the behaviour breaks:

Mutation Result
this[kUrl].origin -> undefined in the client's kDispatch 3 of 4 fail
drop the origin validation in Agent.dispatch 1 of 4 fails
both reverted 4 of 4 pass

One note on that first mutation: I initially tried removing the origin-filling block in lib/dispatcher/dispatcher.js and the tests still passed. That block only runs inside compose(), for interceptor chains — not on the direct dispatch path the tests exercise. Worth knowing for anyone else reviewing this area.

Disclosure

Prepared with AI assistance. Every claim above was executed locally against a real server and a real Node runtime; the mutation checks were run, not assumed.

Fixes #1011

…hers

Fixes nodejs#1011.

`Dispatcher.md` documented the `origin` option of `dispatcher.dispatch()` as
"(optional)", which reads as "never required". That only holds for a dispatcher
already bound to a single origin. `Agent` is not bound to one origin and
requires it.

Verified against current `main`:

  new Pool(origin).request({ path, method })   -> 200
  new Client(origin).request({ path, method })  -> 200
  new Agent().request({ path, method })         -> InvalidArgumentError
                                                'opts.origin must be a
                                                 non-empty string or URL.'
  new Agent().request({ origin, path, method }) -> 200

`Client`/`Pool` fill the origin from `this[kUrl].origin` when `kDispatch` builds
the Request (lib/dispatcher/client.js), while `Agent` rejects a missing origin
in its own `dispatch` (lib/dispatcher/agent.js). `docs/docs/api/Agent.md` already
calls `origin` "Required." for `Agent.dispatch()`; this aligns the abstract
Dispatcher docs with it.

Adds test/node-test/dispatcher-optional-origin.js to pin the distinction, which
had no test coverage.

Validation:
- node --test test/node-test/dispatcher-optional-origin.js   4/4 pass
- node --test test/node-test/agent.js                        35/35 pass
- node --test test/node-test/balanced-pool.js                25/25 pass
- eslint test/node-test/dispatcher-optional-origin.js         clean

Mutation checks, since a passing test is not the same as a protective test:
replacing `this[kUrl].origin` with `undefined` in the client's kDispatch
Request construction fails 3 of the 4 new tests, and dropping the origin
validation in Agent.dispatch fails 1 of 4.

Signed-off-by: Attila <128087784+attilayener@users.noreply.github.com>
@codecov-commenter

codecov-commenter commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.54%. Comparing base (6fa5bb9) to head (2eeb39e).
⚠️ Report is 24 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5994   +/-   ##
=======================================
  Coverage   91.54%   91.54%           
=======================================
  Files         113      113           
  Lines       43597    43597           
=======================================
+ Hits        39910    39912    +2     
+ Misses       3687     3685    -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

Documentation: RequestOptions

4 participants