{"record":{"id":"3a5d6291fb25c165","repo":"vercel/next.js","slug":"method-unavailable-on-readonlyurlsearchparams-r","errorCode":null,"errorMessage":"Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams","messagePattern":"Method unavailable on `ReadonlyURLSearchParams`\\. Read more: https://nextjs\\.org/docs/app/api-reference/functions/use-search-params#updating-searchparams","errorType":"exception","errorClass":"ReadonlyURLSearchParamsError","httpStatus":null,"severity":"error","filePath":"packages/next/src/client/components/readonly-url-search-params.ts","lineNumber":23,"sourceCode":" */\n\n/** @internal */\nclass ReadonlyURLSearchParamsError extends Error {\n  constructor() {\n    super(\n      'Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams'\n    )\n  }\n}\n\n/**\n * A read-only version of URLSearchParams that throws errors when mutation methods are called.\n * This ensures that the URLSearchParams returned by useSearchParams() cannot be mutated.\n */\nexport class ReadonlyURLSearchParams extends URLSearchParams {\n  /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */\n  append() {\n    throw new ReadonlyURLSearchParamsError()\n  }\n  /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */\n  delete() {\n    throw new ReadonlyURLSearchParamsError()\n  }\n  /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */\n  set() {\n    throw new ReadonlyURLSearchParamsError()\n  }\n  /** @deprecated Method unavailable on `ReadonlyURLSearchParams`. Read more: https://nextjs.org/docs/app/api-reference/functions/use-search-params#updating-searchparams */\n  sort() {\n    throw new ReadonlyURLSearchParamsError()\n  }\n}\n","sourceCodeStart":5,"sourceCodeEnd":38,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/packages/next/src/client/components/readonly-url-search-params.ts#L5-L38","documentation":"`useSearchParams()` from `next/navigation` returns a `ReadonlyURLSearchParams` instance that overrides `append()` to throw. The App Router deliberately makes search params read-only on the client because URL state should be managed through the router (router.push/replace), not by mutating the params object directly.","triggerScenarios":"Calling `.append()` on the value returned by `useSearchParams()`. The class extends URLSearchParams but overrides the mutation method to throw a `ReadonlyURLSearchParamsError`.","commonSituations":"Migrating from Pages Router where URLSearchParams was fully mutable; using a URL manipulation helper that expects to call .append(); adding a query param to the current URL in an event handler.","solutions":["Construct a new mutable URLSearchParams from the readonly values, mutate it, then navigate: `const p = new URLSearchParams(searchParams.toString()); p.append('key', 'val'); router.push('?' + p.toString())`.","Use router.push or router.replace with the full updated query string.","Use the `usePathname` + `useRouter` pattern to build the target URL."],"exampleFix":"// before — throws\nconst searchParams = useSearchParams()\nsearchParams.append('page', '2')\n\n// after — build a new URL and navigate\nconst searchParams = useSearchParams()\nconst router = useRouter()\nconst params = new URLSearchParams(searchParams.toString())\nparams.append('page', '2')\nrouter.push(`?${params.toString()}`)","handlingStrategy":"type-guard","validationCode":"import { useSearchParams } from 'next/navigation'\n// Use a writable copy for mutations\nfunction useMutableSearchParams(): URLSearchParams {\n  const readonly = useSearchParams()\n  return new URLSearchParams(readonly.toString())\n}","typeGuard":"import { ReadonlyURLSearchParams } from 'next/navigation'\nfunction isReadonlyURLSearchParams(\n  v: unknown\n): v is ReadonlyURLSearchParams {\n  return v instanceof ReadonlyURLSearchParams\n}","tryCatchPattern":null,"preventionTips":["Never call mutation methods (.append/.delete/.set/.sort) on useSearchParams() return value.","If you need to mutate, create a new URLSearchParams from searchParams.toString() first.","Use router.push/replace to apply URL changes, not direct param mutation."],"tags":["router","search-params","readonly","app-router","use-search-params"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}