Skip to content

Fix searchParams setter dropping the value when a URL is set#2454

Merged
sindresorhus merged 2 commits into
sindresorhus:mainfrom
chatman-media:fix/searchparams-setter-override
Jun 21, 2026
Merged

Fix searchParams setter dropping the value when a URL is set#2454
sindresorhus merged 2 commits into
sindresorhus:mainfrom
chatman-media:fix/searchparams-setter-override

Conversation

@chatman-media

Copy link
Copy Markdown
Contributor

Problem

Assigning to options.searchParams directly on an Options instance silently drops the new value. The query string the request is sent with is unchanged.

This happens outside the option-merging that the constructor uses internally — most notably in a beforeRequest hook, where the docs explicitly encourage mutating options:

import got from 'got';

await got('https://example.com', {
	searchParams: {old: 'value'},
	hooks: {
		beforeRequest: [
			options => {
				options.searchParams = {foo: 'bar'};
			},
		],
	},
});
//=> request goes to https://example.com/?old=value
//   expected: https://example.com/?foo=bar

The searchParams documentation states the value "will override the query string in url", so the request above should be sent with ?foo=bar.

The same applies to a fresh Options instance with no URL yet:

const options = new Options();
options.searchParams = {foo: 'bar'};
options.searchParams.toString(); //=> '' (expected 'foo=bar')

Cause

In the searchParams setter, the incoming value is normalized into a local updated URLSearchParams. The merging branch consumes updated, but both non-merging branches wrote/stored searchParameters (the existing params) instead of updated, so the new value was never applied:

} else if (url) {
	url.search = searchParameters.toString(); // ignores `updated`
} else {
	this.#internals.searchParams = searchParameters; // ignores `updated`
}

The normal got(url, {searchParams}) path was unaffected because it goes through the merging branch, which is why this wasn't caught earlier.

Fix

Use updated in the non-merging branches so the assignment overrides the query string as documented. The merging branch is unchanged.

Added two regression tests covering overriding searchParams from a beforeRequest hook with both an object and a string. Both fail before the change and pass after. The existing arguments, normalize-arguments, hooks, and pagination suites remain green (tsc --noEmit and xo are also clean).

@sindresorhus

Copy link
Copy Markdown
Owner

One thing to fix before merging: direct assignment on a bare Options instance now works, but assigning a URLSearchParams stores the caller-owned object by reference:

const parameters = new URLSearchParams("foo=bar");
const options = new Options();
options.searchParams = parameters;
parameters.set("foo", "changed");
console.log(options.searchParams.toString()); // foo=changed

That seems accidently inconsistent with the constructor / extend path, which clones URLSearchParams. The no-URL assignment branch should store a fresh copy instead.

@chatman-media

Copy link
Copy Markdown
Contributor Author

Good catch, now cloning the URLSearchParams so the caller's object isn't stored by reference. Added a regression test that mutates the caller's instance after assignment and asserts the stored options are unchanged (fails before, passes after).

@sindresorhus
sindresorhus merged commit 5772bf2 into sindresorhus:main Jun 21, 2026
2 checks passed
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