{"record":{"id":"a4862799ba6fc450","repo":"cypress-io/cypress","slug":"params-should-be-a-string-but-got-from-query-pa","errorCode":null,"errorMessage":"params should be a string but got: ${from.query.params}","messagePattern":"params should be a string but got: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/app/src/router/router.ts","lineNumber":49,"sourceCode":"   * @example\n   * // redirects to the Debug page passing a parameter of `from` set to `notification`\n   * \"/redirect?name=Debug&params=%7B%22from%22%3A%22notification%22%7D\"\n   *\n   * @see changeUrlToDebug in packages/server/lib/open_project.ts\n   */\n  routes.push({\n    path: '/redirect',\n    redirect: (from) => {\n      if (from.query.name) {\n        if (typeof from.query.name !== 'string') {\n          throw new Error(`name should be a single string but got: ${from.query.name}`)\n        }\n\n        let params = {}\n\n        if (from.query.params) {\n          if (typeof from.query.params !== 'string') {\n            throw new Error(`params should be a string but got: ${from.query.params}`)\n          }\n\n          try {\n            params = JSON.parse(from.query.params)\n          } catch {\n            throw new Error(`params was not valid JSON: ${from.query.params}`)\n          }\n        }\n\n        return {\n          name: from.query.name,\n          params,\n          query: {}, //reset query params so they do not get passed on\n        }\n      }\n\n      return { path: '/' }\n    },","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/cypress-io/cypress/blob/0d85fdc91230885bca0a91df278312800a48b727/packages/app/src/router/router.ts#L31-L67","documentation":"Thrown by the /redirect route handler when query.params is present but not a string. Same defensive-validation pattern as error 51: query params can be arrays when repeated, and the handler does not know how to JSON.parse an array. The handler then attempts JSON.parse on params, so it requires a string form.","triggerScenarios":"A caller issues /redirect?...&params=A&params=B, or a buggy caller passes params as a non-stringified object via URLSearchParams.set with an object that gets toStringed incorrectly. Most commonly an internal code path that forgets to JSON.stringify the params payload before adding it to the URL.","commonSituations":"Internal Cypress URL construction (changeUrlToDebug) forgetting to JSON.stringify, browser extension duplicating query params, or manual testing of the /redirect endpoint with malformed params.","solutions":["Always JSON.stringify the params object before placing it in the URL: `params.set('params', JSON.stringify(obj))`.","Ensure params appears only once in the query string.","If hitting this from Cypress itself, report a bug — the server should always stringify."],"exampleFix":"// before\nparams.set('params', { from: 'notification' }) // becomes '[object Object]'\n// after\nparams.set('params', JSON.stringify({ from: 'notification' }))","handlingStrategy":"validation","validationCode":"function asString (v: unknown): string | null {\n  return typeof v === 'string' ? v : null\n}\nconst params = asString(from.query.params)\nif (from.query.params && !params) throw new Error('params must be a string')","typeGuard":"function isSingleString (v: unknown): v is string {\n  return typeof v === 'string'\n}","tryCatchPattern":null,"preventionTips":["Always JSON.stringify params before URL insertion.","Use URLSearchParams.set to avoid duplicate keys.","Unit-test redirect URL construction."],"tags":["router","query-validation","internal","app"],"backgroundTag":null,"analyzedSha":"0d85fdc91230885bca0a91df278312800a48b727","analyzedAt":"2026-08-12T16:24:28.056Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}