{"record":{"id":"b68934944d47da48","repo":"vuejs/vue-router","slug":"error-decoding-str-leaving-it-intact","errorCode":null,"errorMessage":"Error decoding \"${str}\". Leaving it intact.","messagePattern":"Error decoding \"(.+?)\"\\. Leaving it intact\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/util/query.js","lineNumber":22,"sourceCode":"\nconst encodeReserveRE = /[!'()*]/g\nconst encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16)\nconst commaRE = /%2C/g\n\n// fixed encodeURIComponent which is more conformant to RFC3986:\n// - escapes [!'()*]\n// - preserve commas\nconst encode = str =>\n  encodeURIComponent(str)\n    .replace(encodeReserveRE, encodeReserveReplacer)\n    .replace(commaRE, ',')\n\nexport function decode (str: string) {\n  try {\n    return decodeURIComponent(str)\n  } catch (err) {\n    if (process.env.NODE_ENV !== 'production') {\n      warn(false, `Error decoding \"${str}\". Leaving it intact.`)\n    }\n  }\n  return str\n}\n\nexport function resolveQuery (\n  query: ?string,\n  extraQuery: Dictionary<string> = {},\n  _parseQuery: ?Function\n): Dictionary<string> {\n  const parse = _parseQuery || parseQuery\n  let parsedQuery\n  try {\n    parsedQuery = parse(query || '')\n  } catch (e) {\n    process.env.NODE_ENV !== 'production' && warn(false, e.message)\n    parsedQuery = {}\n  }","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/vuejs/vue-router/blob/680ccc68c506cca9be6207745043245d61fa715a/src/util/query.js#L4-L40","documentation":"decode wraps decodeURIComponent to decode query string keys and values. Some strings are invalid percent-encoding sequences (e.g. '%', '%zz', or truncated escapes like '%E0%A4' in the middle), and decodeURIComponent throws URIError on them. Instead of failing navigation, the library logs this warning and leaves the string undecoded so the query value is still usable.","triggerScenarios":"Navigating to a URL whose query string contains a malformed percent-escape: e.g. /search?q=100% or /page?name=%E0%A4%A when parseQuery invokes decode on key or val. The raw query string is preserved (intact) rather than decoded.","commonSituations":"Users pasting URLs with unencoded '%' characters (very common: '50% off', '100%'); external systems generating invalid escapes; server redirects carrying already-decoded percent signs; truncated escapes from string slicing/copy-paste.","solutions":["Fix the source of the URL to properly percent-encode: encodeURIComponent('100%') produces '100%25'.","Sanitize/repair the incoming query string before navigation (replace stray '%' with '%25').","On the server, normalize malformed query params before redirecting into the SPA.","If the value is user-supplied and cannot be trusted, decode manually with try/catch and use the raw value (the library already does this — the warning is informational)."],"exampleFix":"// before\nconst url = `/search?q=${term}` // term = '100%'\n// after\nconst url = `/search?q=${encodeURIComponent(term)}` // 'q=100%25'","handlingStrategy":"fallback","validationCode":"function isDecodable (str) {\n  try { decodeURIComponent(str); return true } catch (e) { return false }\n}\n// check query values from external input before navigation","typeGuard":null,"tryCatchPattern":"let q\ntry { q = decodeURIComponent(raw) } catch (e) { q = raw // leave intact, as vue-router does\n  console.warn('undecodable query value:', raw) }","preventionTips":["Always encodeURIComponent user-generated values before building URLs.","Never double-decode strings that may already be decoded.","Sanitize inbound URLs server-side (fix stray '%' before redirecting into the SPA).","Watch for this warning in dev; it means query data is being passed through raw."],"tags":["vue-router","query-string","url-encoding","decodeuri"],"backgroundTag":"malformed-percent-encoding","analyzedSha":"680ccc68c506cca9be6207745043245d61fa715a","analyzedAt":"2026-09-02T19:19:01.204Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}