NousResearch/hermes-agent · warning · Error

Invalid delete

Error message

Invalid delete

What it means

The 'hermes:fs:trash' IPC moves a file/folder to the OS trash via shell.trashItem. Its only input validation is a non-empty trimmed target path; an empty/undefined value throws 'Invalid delete' before the shell call. Failures from trashItem itself surface as different (shell) errors.

Source

Thrown at apps/desktop/electron/main.ts:11819

  const resolved = resolveRequestedPathForIpc(expandUserPath(raw), { purpose: 'Write text file' })

  if (!directoryExists(path.dirname(resolved))) {
    throw new Error('Parent directory does not exist')
  }

  await fs.promises.writeFile(resolved, text, 'utf8')

  return { path: resolved }
})

// Move a file/folder to the OS trash (recoverable) — the VS Code "Delete"
// default. `shell.trashItem` routes to Finder/Explorer/Files trash per platform.
ipcMain.handle('hermes:fs:trash', async (_event, targetPath) => {
  const target = String(targetPath || '').trim()

  if (!target) {
    throw new Error('Invalid delete')
  }

  await shell.trashItem(target)

  return true
})

// Git-driven worktree management ("Start work" flow). Errors surface to the
// renderer as rejected promises so it can toast a friendly message.
ipcMain.handle('hermes:git:worktreeList', async (_event, repoPath) => listWorktrees(repoPath, resolveGitBinary()))

ipcMain.handle('hermes:git:worktreeAdd', async (_event, repoPath, options) =>
  addWorktree(repoPath, options || {}, resolveGitBinary())
)

ipcMain.handle('hermes:git:worktreeRemove', async (_event, repoPath, worktreePath, options) =>
  removeWorktree(repoPath, worktreePath, options || {}, resolveGitBinary())
)

View on GitHub (pinned to c896c09c42)

Solutions

  1. Guard the delete action on a non-empty selected item path in the renderer
  2. Disable the delete affordance when no item is selected
  3. Distinguish this validation error from real trashItem failures (permissions, missing file) which throw different messages

Example fix

// before
onDelete={() => void ipc.invoke('hermes:fs:trash', selected?.path)}

// after
onDelete={() => { if (selected?.path) void ipc.invoke('hermes:fs:trash', selected.path) }}
Defensive patterns

Strategy: validation

Validate before calling

const target = typeof targetPath === 'string' ? targetPath.trim() : ''
if (!target) { notify('Select an item to delete'); return }
await ipc.invoke('hermes:fs:trash', target)

Type guard

function hasTrashTarget(v: unknown): v is string { return typeof v === 'string' && v.trim().length > 0 }

Try / catch

catch (e) { if (e instanceof Error && e.message === 'Invalid delete') notify('Nothing selected to delete') else throw e }

Prevention

When it happens

Trigger: Renderer invokes hermes:fs:trash with '', ' ', null, or undefined — typically a delete action fired from UI state where the selected item's path is not set (nothing selected, or selection cleared by a re-render).

Common situations: Delete button enabled with an empty selection; keyboard shortcut handled before the focused-item state resolves; list virtualization returning null item for the row index.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/3683caabff11ba87. Report an issue: GitHub.