Skip to content

PDF file previews show "Preview not available for application/pdf" #1985

Description

@jsilets

Summary

Opening any PDF in the file preview panel shows an error message instead of
the document. The content routes already serve the bytes with the correct
mime type; the app has no branch for application/pdf, so every PDF falls
through to the unsupported state. Images, video, CSV, and markdown all
render.

Versions and environment

  • bb 0.39.0, desktop app, macOS 26
  • Code path confirmed unchanged on main at b61ec88

To be precise about the repro: I observed the message in the packaged 0.39.0
desktop app, and confirmed by reading main that the same code path still
produces it. I did not click through a from-source build to see the message
a second time.

Steps to reproduce

  1. Open a thread.
  2. Open any PDF in the preview panel, either from a file link in the
    timeline or from a file tab.

Expected vs actual

Expected: the document renders, the way images, video, CSV, and markdown do.

Actual, verbatim:

Preview not available for application/pdf.

The path header and open-in-editor action render normally. Only the body
shows the error.

Evidence

Image

buildFilePreview tests the mime type in this order: image types, known
text types, a UTF-8 fallback, then video types. application/pdf matches
none of them, so the function returns kind unsupported:

export function buildFilePreview(args: BuildFilePreviewArgs): FilePreview {
const base = {
mimeType: args.mimeType,
name: args.name,
path: args.path,
url: args.url,
};
if (args.mimeType.startsWith("image/")) {
return {
kind: "image",
...base,
};
}
if (isKnownTextMimeType(args.mimeType)) {
const textContent = decodeDeclaredTextContent(args.contentBytes);
if (textContent === null) {
return {
kind: "unsupported",
...base,
};
}
return {
kind: "text",
...base,
content: textContent,
};
}
const fallbackTextContent = decodeUtf8Text(args.contentBytes);
if (fallbackTextContent !== null) {
return {
kind: "text",
...base,
content: fallbackTextContent,
};
}
if (args.mimeType.startsWith("video/")) {
return {
kind: "video",
...base,
};
}
return {
kind: "unsupported",
...base,
};
}

SecondaryPanelFilePreview then renders the message above:

return (
<FilePreviewSurface
path={activePath}
copyPath={copyPath}
onSelectionAddToChat={onSelectionAddToChat}
onOpenInEditor={onOpenInEditor}
onRefresh={onRefresh}
isRefreshing={isRefreshing}
statusLabel={statusLabel}
state={{
kind: "error",
message: `Preview not available for ${filePreview.mimeType}.`,
}}
/>
);

The server side already works. Against a dev server built from this
checkout, a GET to /api/v1/threads/:id/host-files/content for a PDF
returns 200, content-type: application/pdf, and the raw bytes.

What you ruled out

  • Not a server or route problem. The content route returns the correct mime
    type and bytes; see above.
  • Not a duplicate. No open or closed issue mentions PDF previews. HEIC images aren't rendered in the UI #1670 is
    the same class of gap (HEIC does not render) but a different format, and
    HEIC needs decoding rather than a new branch.
  • Not configuration. No plugin provides PDF rendering, and nothing in
    settings changes this path.

Suggested priority and effort

Small. Chromium renders a PDF with its built-in viewer when a frame loads an
application/pdf response, so the fix is one new preview kind plus an
iframe, with no PDF library and no new dependency. Same shape and files as
#520, which added CSV previews.

PR open at #1979.

Checks

  • I reproduced this on the latest release or on main, or I say above that I could not.
  • I searched open and closed issues for the same problem.
  • If an agent wrote this, the body ends with > AGENT GENERATED: by <model> and links the thread or report.

AGENT GENERATED: by Claude Opus 5 and Claude Fable 5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions