NousResearch/hermes-agent · warning · Error
Invalid PDF file header
Error message
Invalid PDF file header
What it means
Final content guard in dataUrlToBlob: after successful base64 decode it requires the decoded bytes to start with the literal '%PDF-' magic. Anything else means the payload decoded fine but is not a PDF (HTML error page, PNG, JSON, plain text). This stops the preview from handing a non-PDF blob to the PDF renderer, which would otherwise fail with a cryptic renderer error.
Source
Thrown at apps/desktop/src/app/chat/right-rail/preview-file.tsx:249
.split(';')
.map(part => part.trim().toLowerCase())
const payload = dataUrl.slice(comma + 1)
if (metadata[0] !== 'application/pdf' || !metadata.slice(1).includes('base64')) {
throw new Error('Invalid PDF data URL type')
}
let binary: string
try {
binary = atob(decodeURIComponent(payload))
} catch {
throw new Error('Invalid PDF data URL payload')
}
if (!binary.startsWith('%PDF-')) {
throw new Error('Invalid PDF file header')
}
const bytes = new Uint8Array(binary.length)
for (let index = 0; index < binary.length; index += 1) {
bytes[index] = binary.charCodeAt(index)
}
return new Blob([bytes], { type: 'application/pdf' })
}
async function readTextPreview(filePath: string) {
try {
return await readDesktopFileText(filePath)
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
if (!message.includes("No handler registered for 'hermes:readFileText'")) {View on GitHub (pinned to c896c09c42)
Solutions
- Re-fetch the source document and verify with `curl -I` / `file` that it really is a PDF.
- Fix upstream classification so the attachment kind reflects actual bytes, not the filename extension.
- If the payload is HTML/text, route it to the text/HTML preview instead.
- For producers: set the data URL MIME from the real content type of the streamed bytes.
Example fix
// before
if (!binary.startsWith('%PDF-')) {
throw new Error('Invalid PDF file header')
}
// after — give the user the actual detected type in the error
const header = binary.slice(0, 8)
if (!binary.startsWith('%PDF-')) {
throw new Error(`Invalid PDF file header (got: ${JSON.stringify(header)})`)
} Defensive patterns
Strategy: validation
Validate before calling
const decodedHead = atob(payload.slice(0, 8))
if (!decodedHead.startsWith('%PDF-')) {
// route to text/html/image preview based on sniffed magic bytes instead of failing
} Type guard
const hasPdfMagic = (bytes: Uint8Array): boolean => bytes[0] === 0x25 /* % */ && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46
Try / catch
try { blob = dataUrlToBlob(url) } catch (e) { if (e.message === 'Invalid PDF file header') { offerDownload(url) /* let the user open it externally */ } } Prevention
- Sniff magic bytes at download time and label artifacts by real content type
- Treat HTML responses from download endpoints as errors, not PDFs
- Offer a raw download fallback when preview validation fails
When it happens
Trigger: An application/pdf data URL whose bytes are actually HTML (common when a download endpoint returned an error page but the caller labeled it as PDF), a screenshot image mislabeled as PDF, or an encrypted/patched PDF variant without the standard header offset 0.
Common situations: Signed/expired download links returning HTML login pages saved as .pdf; tools labeling all document artifacts 'pdf'; zero-byte or header-shifted payloads after bad decoding.
Related errors
- Invalid PDF data URL
- Invalid PDF data URL payload
- Invalid PDF data URL type
- Branch name is required.
- Missing URL
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/07fd2dfb05019ef5.
Report an issue: GitHub.