{"id":"20f4004949274a13","repo":"sindresorhus/got","slug":"parameters-search-and-searchparams-are-mutuall","errorCode":null,"errorMessage":"Parameters `search` and `searchParams` are mutually exclusive.","messagePattern":"Parameters `search` and `searchParams` are mutually exclusive\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"source/core/utils/options-to-url.ts","lineNumber":39,"sourceCode":"];\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}\n\n\tconst url = new URL(origin);\n\n\tif (options.path) {\n\t\tconst searchIndex = options.path.indexOf('?');\n\t\tif (searchIndex === -1) {\n\t\t\toptions.pathname = options.path;\n\t\t} else {\n\t\t\toptions.pathname = options.path.slice(0, searchIndex);","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/utils/options-to-url.ts#L21-L57","documentation":"options-to-url.ts:39: `search` (a raw query string like `'a=1&b=2'`) and `searchParams` (a structured object/URLSearchParams) cannot both be set. They both target `url.search`, so providing both is ambiguous; Got refuses rather than silently concatenating or overwriting.","triggerScenarios":"Passing `{search: 'a=1', searchParams: {b: 2}}` in one options object, or merging defaults that carry `searchParams` with a call that sets `search` (or vice-versa).","commonSituations":"Refactoring from raw `search` strings to structured `searchParams` and leaving both fields populated; combining two example snippets; a helper that sets `search` while a caller adds `searchParams`.","solutions":["Standardize on one query API — `searchParams` (structured) is preferred for new code.","If migrating, convert legacy `search` strings to `URLSearchParams`/objects once at the boundary and drop `search`.","Audit shared defaults to ensure they don't carry `search` while per-call code uses `searchParams`.","Add a type that marks the two fields mutually exclusive in your own option builder."],"exampleFix":"// before\nawait got(url, {search: 'a=1', searchParams: {b: 2}});\n\n// after\nawait got(url, {searchParams: {a: 1, b: 2}});","handlingStrategy":"validation","validationCode":"function assertOneQueryField(options) {\n  if (options.search && options.searchParams) {\n    throw new TypeError('pass query via search or searchParams, not both');\n  }\n}","typeGuard":"const queryFieldsConsistent = (o: {search?: string; searchParams?: unknown}): boolean =>\n  !(o.search && o.searchParams);","tryCatchPattern":null,"preventionTips":["Standardize on `searchParams` for structured queries.","Convert legacy `search` strings to `URLSearchParams` once at the boundary.","Validate option objects before calling Got.","Unit-test the builder for the conflict."],"tags":["url","validation","options"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}