cypress-io/cypress · warning · Error

params should be a string but got: ${from.query.params}

Error message

params should be a string but got: ${from.query.params}

What it means

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.

Source

Thrown at packages/app/src/router/router.ts:49

   * @example
   * // redirects to the Debug page passing a parameter of `from` set to `notification`
   * "/redirect?name=Debug&params=%7B%22from%22%3A%22notification%22%7D"
   *
   * @see changeUrlToDebug in packages/server/lib/open_project.ts
   */
  routes.push({
    path: '/redirect',
    redirect: (from) => {
      if (from.query.name) {
        if (typeof from.query.name !== 'string') {
          throw new Error(`name should be a single string but got: ${from.query.name}`)
        }

        let params = {}

        if (from.query.params) {
          if (typeof from.query.params !== 'string') {
            throw new Error(`params should be a string but got: ${from.query.params}`)
          }

          try {
            params = JSON.parse(from.query.params)
          } catch {
            throw new Error(`params was not valid JSON: ${from.query.params}`)
          }
        }

        return {
          name: from.query.name,
          params,
          query: {}, //reset query params so they do not get passed on
        }
      }

      return { path: '/' }
    },

View on GitHub (pinned to 0d85fdc912)

Solutions

  1. Always JSON.stringify the params object before placing it in the URL: `params.set('params', JSON.stringify(obj))`.
  2. Ensure params appears only once in the query string.
  3. If hitting this from Cypress itself, report a bug — the server should always stringify.

Example fix

// before
params.set('params', { from: 'notification' }) // becomes '[object Object]'
// after
params.set('params', JSON.stringify({ from: 'notification' }))
Defensive patterns

Strategy: validation

Validate before calling

function asString (v: unknown): string | null {
  return typeof v === 'string' ? v : null
}
const params = asString(from.query.params)
if (from.query.params && !params) throw new Error('params must be a string')

Type guard

function isSingleString (v: unknown): v is string {
  return typeof v === 'string'
}

Prevention

When it happens

Trigger: 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.

Common situations: Internal Cypress URL construction (changeUrlToDebug) forgetting to JSON.stringify, browser extension duplicating query params, or manual testing of the /redirect endpoint with malformed params.

Related errors


AI-assisted analysis of cypress-io/cypress@0d85fdc912 (2026-08-12). Data as JSON: /api/errors/a4862799ba6fc450. Report an issue: GitHub.