{"record":{"id":"3c38c52a09e7f823","repo":"grafana/grafana","slug":"error-validating-request-path","errorCode":null,"errorMessage":"Error validating request path","messagePattern":"Error validating request path","errorType":"exception","errorClass":"PathValidationError","httpStatus":null,"severity":"warning","filePath":"packages/grafana-data/src/text/sanitize.ts","lineNumber":178,"sourceCode":"    }\n\n    // Validate the entire decoded string for traversal attempts\n    // This prevents attacks that use query separators to hide traversal payloads\n    if (/\\.\\.|\\/\\\\|[\\t\\n\\r]/.test(decoded)) {\n      throw new PathValidationError();\n    }\n\n    // Return the original path (not the decoded version) to preserve the full URL\n    return path;\n  } catch (err) {\n    // Rethrow the original PathValidationError to preserve the stack trace\n    if (err instanceof PathValidationError) {\n      throw err;\n    }\n\n    // A decoding error can happen with malformed URIs (e.g., % not followed by hex).\n    // These are suspicious, so we treat them as traversal attempts.\n    throw new PathValidationError('Error validating request path');\n  }\n}\n\nexport const textUtil = {\n  escapeHtml,\n  hasAnsiCodes,\n  sanitize,\n  sanitizeTextPanelContent,\n  sanitizeUrl,\n  sanitizeSVGContent,\n  sanitizeTrustedTypes,\n  sanitizeTrustedTypesRSS,\n};\n","sourceCodeStart":160,"sourceCodeEnd":192,"githubUrl":"https://github.com/grafana/grafana/blob/ae3104e3690e28e72c8f0c97efc12647a70f75c3/packages/grafana-data/src/text/sanitize.ts#L160-L192","documentation":"Thrown as PathValidationError('Error validating request path') by the catch block in the path validator when URI decoding itself fails (e.g. a '%' not followed by two hex digits). Malformed encodings are treated as suspicious and rejected as potential traversal/smuggling attempts rather than being silently passed through.","triggerScenarios":"Calling the sanitizer on a path containing a stray '%' not followed by valid hex, or any other malformed percent-encoding that makes decodeURIComponent throw. Examples: '/a%2', '/foo%zz', '/%'.","commonSituations":"User input or scraped content with a literal percent sign that was never encoded as %25; truncated URLs; copy-paste from a source that broke the encoding; buggy URL construction that interpolates raw values.","solutions":["Properly percent-encode literal '%' as '%25' before passing the path to the sanitizer.","Validate and repair encoding upstream (encodeURIComponent on dynamic segments) so the path is well-formed.","Catch PathValidationError and show a friendly error to the user instead of letting it propagate.","Reject paths containing a lone '%' at the input boundary."],"exampleFix":"// before\nsanitizeUrl('/download/50%off');\n// after\nsanitizeUrl('/download/50%25off');","handlingStrategy":"try-catch","validationCode":"import { PathValidationError, textUtil } from '@grafana/data';\n\nfunction sanitizeOrFallback(url: string): string {\n  try {\n    return textUtil.sanitizeUrl(url);\n  } catch (e) {\n    if (e instanceof PathValidationError) return '';\n    throw e;\n  }\n}","typeGuard":"function isWellFormedUri(s: string): boolean {\n  try { decodeURIComponent(s); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  clean = textUtil.sanitizeUrl(input);\n} catch (e) {\n  if (e instanceof PathValidationError) {\n    // malformed encoding - treat as invalid URL\n    clean = '';\n  } else throw e;\n}","preventionTips":["Percent-encode literal '%' as '%25' before sanitizing.","Use encodeURIComponent on dynamic path segments.","Catch PathValidationError and present a friendly validation message."],"tags":["security","sanitization","url-encoding","path-traversal"],"backgroundTag":null,"analyzedSha":"ae3104e3690e28e72c8f0c97efc12647a70f75c3","analyzedAt":"2026-08-12T12:48:38.752Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}