sindresorhus/got · error · TypeError
The `url` option is mutually exclusive with the `input` argu
Error message
The `url` option is mutually exclusive with the `input` argument
What it means
Thrown by the Options constructor when a request supplies both a positional `input` argument (the first `got(url, options)` parameter) and an `options.url` property. Got treats the first argument and `options.url` as two ways to set the same value, so providing both is ambiguous and rejected. This guard lives in the constructor so the conflict is caught at option-merge time, before any network activity.
Source
Thrown at source/core/options.ts:1665
//
/* eslint-disable no-unsafe-finally -- `finally` is used intentionally here to ensure `url` is always set last, overwriting any merged searchParams */
try {
if (is.plainObject(input)) {
try {
this.merge(input);
this.merge(options);
} finally {
this.url = input.url;
}
} else {
try {
this.merge(options);
} finally {
if (options?.url !== undefined) {
if (input === undefined) {
this.url = options.url;
} else {
throw new TypeError('The `url` option is mutually exclusive with the `input` argument');
}
} else if (input !== undefined) {
this.url = input;
}
}
}
} catch (error) {
(error as OptionsError).options = this;
throw error;
}
/* eslint-enable no-unsafe-finally */
}
merge(options?: OptionsInit | Options) {
if (!options) {
return;
}View on GitHub (pinned to e3924aa1e5)
Solutions
- Remove `url` from the options object and pass the URL only as the first argument: `got(url, options)`.
- If you must keep the URL in options, call `got(options)` with the options object as the single argument and pass nothing positionally.
- Audit where the options object is assembled and delete any leftover `url` property before the call.
Example fix
// before
await got('https://api.example.com', {url: 'https://api.example.com', json: true});
// after
await got('https://api.example.com', {json: true}); Defensive patterns
Strategy: validation
Validate before calling
function assertNoUrlConflict(input, options) {
if (input !== undefined && options && Object.prototype.hasOwnProperty.call(options, 'url')) {
throw new TypeError('Cannot pass both an `input` argument and `options.url`; pick one.');
}
}
// before calling:
assertNoUrlConflict(url, opts);
await got(url, opts); Type guard
function hasMutuallyExclusiveUrl(input, options): input is string | URL {
return input !== undefined && Boolean(options && 'url' in options);
} Try / catch
try {
await got(url, opts);
} catch (error) {
if (error instanceof Error && /mutually exclusive/.test(error.message)) {
delete opts.url; // recover by dropping the duplicate
return got(url, opts);
}
throw error;
} Prevention
- Treat the URL as either the first argument OR options.url, never both.
- When building options dynamically, delete the `url` key if you also pass it positionally.
- Add a unit test asserting your request helper does not emit both.
When it happens
Trigger: Calling `got('https://a.com', {url: 'https://b.com'})`, or `got(input, {url})` where `input` is a non-undefined string/URL and the options object also contains a `url` key. Also reachable via `new Options(url, {url})` or `got.extend({url}).extend({url})` style merges that feed both paths.
Common situations: Code that builds an options object dynamically and accidentally leaves a stale `url` key in it while also passing the URL positionally; refactors that move the URL from options into the first argument without deleting the old key; spreading a cached config `{...config, url}` and also passing `config.endpoint` as the first arg.
Related errors
- Missing `url` property
- The defaults must be passed as the third argument
- Unexpected option: ${key}
- Unexpected agent option: ${key}
- Unexpected timeout option: ${key}
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/e14c653bbec82694.json.
Report an issue: GitHub.