NousResearch/hermes-agent · warning · Error
Could not open preview target: ${item.target}
Error message
Could not open preview target: ${item.target} What it means
Thrown by PreviewStatusRow in the desktop composer's status stack when the user clicks to open a detected artifact and normalizeOrLocalPreviewTarget fails to resolve item.target (with item.cwd) into anything previewable. The throw is caught by the row's toggle flow and typically surfaced as a failed open action; it distinguishes 'target unresolvable' from 'preview pane open failed'.
Source
Thrown at apps/desktop/src/app/chat/composer/status-stack/preview-row.tsx:33
interface PreviewStatusRowProps {
item: PreviewArtifact
onDismiss: (id: string) => void
}
/** One detected artifact, single line, always visible: filename + open + close. */
export const PreviewStatusRow = memo(function PreviewStatusRow({ item, onDismiss }: PreviewStatusRowProps) {
const { t } = useI18n()
const openSources = useStore($previewTabSources)
const [opening, setOpening] = useState(false)
// A tab open IS a pane in the tree now, so its presence is the whole answer.
const isOpen = openSources.includes(item.target)
const resolveTarget = async () => {
const target = await normalizeOrLocalPreviewTarget(item.target, item.cwd || undefined)
if (!target) {
throw new Error(`Could not open preview target: ${item.target}`)
}
return target
}
const togglePreview = async () => {
if (opening) {
return
}
if (isOpen) {
closePreviewForSource(item.target)
return
}
setOpening(true)
View on GitHub (pinned to c896c09c42)
Solutions
- Confirm the artifact file still exists at the resolved location; if it was cleaned, re-run the generating command.
- Ensure item.cwd is populated so relative targets resolve; if the detector emits bare filenames, make it emit absolute paths.
- For remote backends, preview only targets reachable from the client (local mount or http URL).
- As a developer: catch this error in togglePreview and show a toast with item.target so users see which artifact failed.
Example fix
// before
const resolveTarget = async () => {
const target = await normalizeOrLocalPreviewTarget(item.target, item.cwd || undefined)
if (!target) {
throw new Error(`Could not open preview target: ${item.target}`)
}
return target
}
// after — fall back to an absolute-path attempt before giving up
const resolveTarget = async () => {
const target = (await normalizeOrLocalPreviewTarget(item.target, item.cwd || undefined))
?? (await normalizeOrLocalPreviewTarget(item.absolutePath ?? item.target, undefined))
if (!target) {
throw new Error(`Could not open preview target: ${item.target}`)
}
return target
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!item.target || !(item.target.startsWith('/') || /^https?:/.test(item.target) || item.cwd)) {
// cannot resolve a bare target without a cwd — mark the row unopenable
return null
} Type guard
interface PreviewItem { target: string; cwd?: string }
const isResolvablePreviewItem = (i: PreviewItem): boolean =>
i.target.startsWith('/') || /^https?:/.test(i.target) || Boolean(i.cwd) Try / catch
const togglePreview = async () => {
if (opening) return
try {
const target = await resolveTarget()
openPreview(target, 'status-row')
} catch (error) {
notifyError(error, `Preview unavailable for ${item.target}`)
} finally {
setOpening(false)
}
} Prevention
- Emit absolute paths from the artifact detector so cwd is irrelevant
- Populate item.cwd whenever the target is relative
- Disable the open button for targets that failed resolution before (cache failures per source)
When it happens
Trigger: Clicking the open/toggle control on a preview status row whose item.target is a relative path that cannot be anchored (item.cwd missing or stale), a path to a file that was deleted since detection, or a remote/SSH-only path on a backend the local resolver cannot reach.
Common situations: Artifacts detected from terminal output in remote sessions (paths exist only on the backend), build artifacts cleaned between detection and click, cwd-relative targets after the session's working directory changed.
Related errors
- c.couldNotPreview(attachment.label)
- 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/db3e157d4c2116f1.
Report an issue: GitHub.