{"id":"55bb8f35cd2f4e6e","repo":"sindresorhus/got","slug":"parameters-path-and-search-are-mutually-exclus","errorCode":null,"errorMessage":"Parameters `path` and `search` are mutually exclusive.","messagePattern":"Parameters `path` and `search` are mutually exclusive\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"source/core/utils/options-to-url.ts","lineNumber":30,"sourceCode":"};\n\nconst keys: Array<Exclude<keyof URLOptions, 'searchParams' | 'path'>> = [\n\t'protocol',\n\t'host',\n\t'hostname',\n\t'port',\n\t'pathname',\n\t'search',\n];\n\nexport default function optionsToUrl(origin: string, options: URLOptions): URL {\n\tif (options.path) {\n\t\tif (options.pathname) {\n\t\t\tthrow new TypeError('Parameters `path` and `pathname` are mutually exclusive.');\n\t\t}\n\n\t\tif (options.search) {\n\t\t\tthrow new TypeError('Parameters `path` and `search` are mutually exclusive.');\n\t\t}\n\n\t\tif (options.searchParams) {\n\t\t\tthrow new TypeError('Parameters `path` and `searchParams` are mutually exclusive.');\n\t\t}\n\t}\n\n\tif (options.search && options.searchParams) {\n\t\tthrow new TypeError('Parameters `search` and `searchParams` are mutually exclusive.');\n\t}\n\n\tif (!origin) {\n\t\tif (!options.protocol) {\n\t\t\tthrow new TypeError('No URL protocol specified');\n\t\t}\n\n\t\torigin = `${options.protocol}//${options.hostname ?? options.host ?? ''}`;\n\t}","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/utils/options-to-url.ts#L12-L48","documentation":"options-to-url.ts:30: `path` (which may embed a `?query`) cannot be combined with an explicit `search` option. Since `path` already carries its own query portion, providing `search` separately makes the resulting URL ambiguous; Got refuses rather than silently dropping one.","triggerScenarios":"Passing `{path: '/list?page=1', search: 'q=2'}` — the `?page=1` inside path conflicts with the explicit `search`. Also fires when merging defaults that carry `search` into a call using `path`.","commonSituations":"Combining a Node-core-style `path` option with a Got-style `search`; layering query builders that each set a different field; refactoring from `path` to `searchParams` mid-migration.","solutions":["Pick one query mechanism: either embed the query in `path`, or use `search`/`searchParams` with a query-free `path`/`pathname`.","If you need both programmatic and path-embedded queries, normalize upstream so only one wins.","Remove `search` from shared defaults if per-call `path` carries its own query.","Use `searchParams` (URLSearchParams) for programmatic query construction and drop `path`."],"exampleFix":"// before\nawait got(url, {path: '/list?page=1', search: 'q=2'});\n\n// after\nawait got(url, {pathname: '/list', searchParams: {page: 1, q: 2}});","handlingStrategy":"validation","validationCode":"function assertNoPathSearchConflict(options) {\n  if (options.path && options.search) {\n    throw new TypeError('pass query via path or via search, not both');\n  }\n}","typeGuard":"const pathAndSearchConsistent = (o: {path?: string; search?: string}): boolean =>\n  !(o.path && o.search);","tryCatchPattern":null,"preventionTips":["Use one query mechanism consistently (prefer `searchParams`).","Strip `search` from defaults when per-call `path` is used.","Validate option objects in a builder helper.","Unit-test the option builder for conflicts."],"tags":["url","validation","options"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}