{"record":{"id":"a711a0db09da72e6","repo":"remix-run/remix","slug":"dangling-escape","errorCode":null,"errorMessage":"dangling escape","messagePattern":"dangling escape","errorType":"validation","errorClass":"ParseError","httpStatus":null,"severity":"error","filePath":"packages/route-pattern/src/lib/route-pattern/parse.ts","lineNumber":122,"sourceCode":"    if (char === '*') {\n      i += 1\n      let name = IDENTIFIER_RE.exec(source.slice(i, span[1]))?.[0]\n      tokens.push({ type: '*', name: name ?? '*' })\n      tokenIndices.push(i - 1)\n      i += name?.length ?? 0\n      continue\n    }\n\n    if (char === separator) {\n      tokens.push({ type: 'separator' })\n      tokenIndices.push(i)\n      i += 1\n      continue\n    }\n\n    if (char === '\\\\') {\n      if (i + 1 === span[1]) {\n        throw new ParseError('dangling escape', source, i)\n      }\n      let text = source.slice(i + 1, i + 2)\n      appendText(text)\n      i += 2\n      continue\n    }\n\n    appendText(char)\n    i += 1\n  }\n  let unmatchedOptional = optionalStack.at(-1)\n  if (unmatchedOptional !== undefined) {\n    throw new ParseError('unmatched (', source, unmatchedOptional.sourceIndex)\n  }\n  if (emptyOptionals.length > 0) {\n    throw new ParseError('empty optional', source, emptyOptionals[0])\n  }\n","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/route-pattern/src/lib/route-pattern/parse.ts#L104-L140","documentation":"Pattern syntax supports backslash escapes for literal special characters. A backslash was found at the very end of the part span with nothing after it to escape, so it cannot form a valid escape sequence. parsePart throws 'dangling escape' at the backslash's index.","triggerScenarios":"Calling parseRoutePattern with a pattern ending in an unpaired '\\', e.g. '/files/docs\\\\' or 'C\\\\' style Windows-ish fragments, or where string interpolation dropped the escaped character.","commonSituations":"JS string templating where '\\\\' was meant to be a literal backslash but ended up as the pattern's escape char with no following char; truncation during edits; escaping a separator incorrectly.","solutions":["Remove the trailing backslash or escape it as '\\\\\\\\' if a literal backslash is intended","Double-check JS string escaping — in a JS literal '\\\\\\\\' is one backslash in the pattern","Use the error position to find the dangling escape"],"exampleFix":"// before\nlet pattern = parseRoutePattern('/files/docs\\\\')\n\n// after\nlet pattern = parseRoutePattern('/files/docs')","handlingStrategy":"validation","validationCode":"if (source.endsWith('\\\\') && !source.endsWith('\\\\\\\\')) throw new Error('Dangling escape in pattern')","typeGuard":"null","tryCatchPattern":"try { parseRoutePattern(source) } catch (e) { if (e instanceof ParseError && e.message === 'dangling escape') { /* fix or trim trailing backslash */ } }","preventionTips":["Remember JS strings double-escape backslashes","Validate generated patterns before registration"],"tags":["route-pattern","parse","syntax","escaping"],"backgroundTag":"invalid-route-pattern-syntax","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}