{"record":{"id":"a9e408769f2d1bbe","repo":"NousResearch/hermes-agent","slug":"invalid-pdf-data-url","errorCode":null,"errorMessage":"Invalid PDF data URL","messagePattern":"Invalid PDF data URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/desktop/src/app/chat/right-rail/preview-file.tsx","lineNumber":226,"sourceCode":"\n  for (const byte of bytes.slice(0, 4096)) {\n    if (byte === 0) {\n      return true\n    }\n\n    if (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {\n      suspicious += 1\n    }\n  }\n\n  return suspicious / Math.min(bytes.length, 4096) > 0.12\n}\n\nfunction dataUrlToBlob(dataUrl: string) {\n  const comma = dataUrl.indexOf(',')\n\n  if (comma < 0 || !dataUrl.startsWith('data:')) {\n    throw new Error('Invalid PDF data URL')\n  }\n\n  const metadata = dataUrl\n    .slice(5, comma)\n    .split(';')\n    .map(part => part.trim().toLowerCase())\n\n  const payload = dataUrl.slice(comma + 1)\n\n  if (metadata[0] !== 'application/pdf' || !metadata.slice(1).includes('base64')) {\n    throw new Error('Invalid PDF data URL type')\n  }\n\n  let binary: string\n\n  try {\n    binary = atob(decodeURIComponent(payload))\n  } catch {","sourceCodeStart":208,"sourceCodeEnd":244,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/src/app/chat/right-rail/preview-file.tsx#L208-L244","documentation":"First guard in dataUrlToBlob (preview-file.tsx) which converts a PDF data URL into a Blob for in-app preview. It requires the string to start with the literal 'data:' prefix and contain a comma separating metadata from payload. Missing either means the input is not a data URL at all (e.g. a plain URL, a file path, or a truncated/garbled payload), so the parser refuses it before inspecting the media type.","triggerScenarios":"Calling the PDF preview path with a value that is not a data URL: an http(s) URL to a PDF, a local file path, a blob: URL, or a data URL whose comma was stripped by URL encoding/trimming upstream.","commonSituations":"Tool results or attachment metadata carrying a remote PDF URL being routed into the data-URL preview branch; copy/paste truncation; an upstream step that encodeURIComponent'd the whole data URL so the comma became %2C.","solutions":["Route only genuine data: URLs (application/pdf;base64,...) into dataUrlToBlob; branch on startsWith('data:') earlier in the caller.","If the source is an http URL or file path, use the corresponding preview loader instead of the data-URL one.","Fix the upstream producer so the comma and base64 payload are not double-encoded.","DecodeURIComponent the candidate before this check if your pipeline URL-encodes data URLs."],"exampleFix":"// before\nfunction dataUrlToBlob(dataUrl: string) {\n  const comma = dataUrl.indexOf(',')\n  if (comma < 0 || !dataUrl.startsWith('data:')) {\n    throw new Error('Invalid PDF data URL')\n  }\n  // ...\n}\n\n// after — normalize an encoded data URL before validating\nfunction dataUrlToBlob(rawInput: string) {\n  const dataUrl = rawInput.includes('%2C') ? decodeURIComponent(rawInput) : rawInput\n  const comma = dataUrl.indexOf(',')\n  if (comma < 0 || !dataUrl.startsWith('data:')) {\n    throw new Error('Invalid PDF data URL')\n  }\n  // ...\n}","handlingStrategy":"type-guard","validationCode":"const looksLikeDataUrl = (s: string) => /^data:[^,]*,/i.test(s)\nif (!looksLikeDataUrl(candidate)) {\n  routeToNonDataUrlPreview(candidate) // http/file/blob path\n}","typeGuard":"const isPdfDataUrl = (s: string): boolean => /^data:application\\/pdf;base64,/i.test(s)","tryCatchPattern":"try {\n  const blob = dataUrlToBlob(dataUrl)\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('Invalid PDF data URL')) {\n    // fall back to download/raw display rather than failing the whole preview\n  } else throw error\n}","preventionTips":["Branch on startsWith('data:') before calling the PDF converter","Never URL-encode whole data URLs in transit","Add a fast regex pre-check for the exact data:application/pdf;base64, prefix"],"tags":["desktop","preview","pdf","data-url","validation"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}