NousResearch/hermes-agent · warning · Error
c.couldNotPreview(attachment.label)
Error message
c.couldNotPreview(attachment.label)
What it means
Thrown in the desktop chat composer's attachment preview handler (attachments.tsx). After the user asks to preview an attachment target (a path or URL extracted from the attachment), normalizeOrLocalPreviewTarget resolves it against the session cwd; if resolution yields nothing usable (no local file, no reachable URL), the code throws a localized 'could not preview <label>' error instead of silently doing nothing. The surrounding catch shows an error notification, so this is a user-facing 'preview target unresolvable' signal, not a crash.
Source
Thrown at apps/desktop/src/app/chat/composer/attachments.tsx:98
const rawTarget =
attachment.path ||
attachment.detail ||
attachment.refText?.replace(/^@(file|image|url):/, '') ||
attachment.label ||
''
const target = rawTarget.replace(/^`|`$/g, '')
if (!target) {
return
}
try {
const preview = await normalizeOrLocalPreviewTarget(target, cwd || undefined)
if (!preview) {
throw new Error(c.couldNotPreview(attachment.label))
}
openPreview(preview, 'manual')
} catch (error) {
notifyError(error, c.previewUnavailable)
}
}
return (
<>
<Tip label={attachment.path || attachment.detail || attachment.label}>
<div className="group/attachment relative min-w-0 shrink-0">
<button
aria-busy={isUploading || undefined}
aria-label={canPreview ? c.previewLabel(attachment.label) : attachment.label}
className={cn(
'flex max-w-56 items-center gap-2 rounded-2xl border bg-background/50 px-2 py-1.5 text-left shadow-[inset_0_1px_0_rgba(255,255,255,0.18)] transition-colors disabled:cursor-default',
hasUploadErrorView on GitHub (pinned to c896c09c42)
Solutions
- Verify the attachment path exists locally (or on the machine the preview resolver runs on) and that the session cwd is correct.
- If the backend is remote, mount/sync the backend filesystem or use a target the resolver supports (absolute local path or http(s) URL).
- For developers: check normalizeOrLocalPreviewTarget's accepted schemes and make the attachment carry an absolute path or explicit cwd.
- Update a stale attachment payload — re-attach the file instead of previewing a dangling reference.
Example fix
// before
const preview = await normalizeOrLocalPreviewTarget(target, cwd || undefined)
if (!preview) {
throw new Error(c.couldNotPreview(attachment.label))
}
// after — give the resolver a real anchor and surface why it failed
const preview = await normalizeOrLocalPreviewTarget(
attachment.path?.startsWith('/') ? attachment.path : joinPath(cwd, target),
cwd || undefined
)
if (!preview) {
throw new Error(c.couldNotPreview(attachment.path || attachment.label))
} Defensive patterns
Strategy: try-catch
Validate before calling
const target = rawTarget.replace(/^`|`$/g, '')
const isPreviewable = target && (target.startsWith('/') || target.startsWith('http'))
if (!isPreviewable) return // don't attempt preview for unanchorable targets Type guard
const isPreviewableTarget = (t: string | undefined): t is string =>
Boolean(t) && (/^https?:\/\//.test(t!) || t!.startsWith('/') || t!.startsWith('~')) Try / catch
try {
const preview = await normalizeOrLocalPreviewTarget(target, cwd || undefined)
if (!preview) throw new Error(c.couldNotPreview(attachment.label))
openPreview(preview, 'manual')
} catch (error) {
// surfaced as toast, not a crash — keep it that way
notifyError(error, c.previewUnavailable)
} Prevention
- Carry absolute paths (or explicit cwd) in attachment metadata
- For remote backends, only expose preview for client-reachable targets
- Feature-detect the preview action in the UI instead of relying on the thrown error
When it happens
Trigger: Clicking preview/open on an attachment whose target is a remote path from another machine (SSH-backed session), a path that no longer exists (file deleted or cwd changed), a bare filename that normalizeOrLocalPreviewTarget cannot anchor to the supplied cwd, or a URL scheme the preview normalizer rejects.
Common situations: Desktop app connected to a remote backend over URL+token where attachment paths refer to the backend's filesystem, not the local one; sessions resumed after the working directory moved; attachment metadata produced by an older schema where path/detail fields are empty.
Related errors
- Could not open preview target: ${item.target}
- r.couldNotPreview(path)
- Not a directory: ${watchDir}
- Invalid preview URL
- Could not create directory: ${error.message}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/57b727b9296b01c1.
Report an issue: GitHub.