{"record":{"id":"222f0482a9641591","repo":"remix-run/remix","slug":"invalid-bypass-pattern-json-stringify-pattern-222f04","errorCode":null,"errorMessage":"invalid bypass pattern ${JSON.stringify(pattern)}: query strings and fragments are not supported","messagePattern":"invalid bypass pattern (.+?): query strings and fragments are not supported","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cop-middleware/src/lib/cop.ts","lineNumber":249,"sourceCode":"  let pathname = trimmedPattern\n  let methodPattern = /^([A-Z]+)\\s+(.+)$/.exec(trimmedPattern)\n\n  if (methodPattern != null && methodPattern[2].startsWith('/')) {\n    let maybeMethod = methodPattern[1]\n    if (!isRequestMethod(maybeMethod)) {\n      throw new Error(`invalid request method in bypass pattern ${JSON.stringify(pattern)}`)\n    }\n\n    method = maybeMethod\n    pathname = methodPattern[2]\n  }\n\n  if (!pathname.startsWith('/')) {\n    throw new Error(`invalid bypass pattern ${JSON.stringify(pattern)}: path must start with \"/\"`)\n  }\n\n  if (pathname.includes('?') || pathname.includes('#')) {\n    throw new Error(\n      `invalid bypass pattern ${JSON.stringify(pattern)}: query strings and fragments are not supported`,\n    )\n  }\n\n  let matchesSubtree = pathname.endsWith('/')\n  let normalizedPathname =\n    pathname.length > 1 && matchesSubtree ? pathname.slice(0, pathname.length - 1) : pathname\n  let rawSegments = normalizedPathname === '/' ? [] : normalizedPathname.slice(1).split('/')\n  let segments = rawSegments.map((segment, index) =>\n    parseBypassSegment(pattern, segment, index === rawSegments.length - 1),\n  )\n\n  return { method, pathname, segments, matchesSubtree }\n}\n\nfunction parseBypassSegment(\n  pattern: string,\n  segment: string,","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/cop-middleware/src/lib/cop.ts#L231-L267","documentation":"parseBypassPattern rejects bypass patterns whose path contains '?' or '#'. Bypass matching operates on the pathname only; query strings and fragments are deliberately unsupported because bypass decisions should not depend on those URL components. Including them is treated as a configuration mistake.","triggerScenarios":"addInsecureBypassPattern('/search?q=1'), addInsecureBypassPattern('/products#details'), or any pattern where the path portion contains a '?' or '#' character anywhere.","commonSituations":"Copying a full URL with query parameters from a browser into a bypass list; attempting to bypass only requests carrying a specific query parameter; pasting a route that includes a hash anchor.","solutions":["Strip the query string and fragment from the pattern: use '/search' instead of '/search?q=1'","If you need query-dependent behavior, implement it in middleware logic inspecting URLSearchParams, not in the bypass pattern"],"exampleFix":"// before\ncop.addInsecureBypassPattern('/search?q=1')\n// after\ncop.addInsecureBypassPattern('/search')","handlingStrategy":"validation","validationCode":"function isValidBypassPath(pattern: string): boolean {\n  const path = pattern.includes(' ') ? pattern.slice(pattern.indexOf(' ') + 1) : pattern\n  return !path.includes('?') && !path.includes('#')\n}","typeGuard":"const isQueryFree = (p: string) => !/[?#]/.test(p)","tryCatchPattern":"try { cop.addInsecureBypassPattern(p) } catch (e) { if (e instanceof Error && e.message.includes('query strings and fragments')) { p = p.split(/[?#]/)[0] } else throw e }","preventionTips":["Strip URL search/hash before pasting URLs into bypass config","Document that bypass matching is pathname-only"],"tags":["cop-middleware","bypass-pattern","query-string","validation"],"backgroundTag":"invalid-path-pattern","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}