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

  1. Remove `url` from the options object and pass the URL only as the first argument: `got(url, options)`.
  2. If you must keep the URL in options, call `got(options)` with the options object as the single argument and pass nothing positionally.
  3. 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

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


AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03). Data as JSON: /data/errors/e14c653bbec82694.json. Report an issue: GitHub.