NousResearch/hermes-agent · warning · Error
Invalid rename
Error message
Invalid rename
What it means
The 'hermes:fs:rename' IPC renames an item within its parent directory. Before touching the filesystem it validates inputs: src and the new base name must be non-empty, the name must not be '.', '..', or contain '/' or '\\'. Any violation throws 'Invalid rename' — the design guarantees a rename can never traverse out of its parent dir or become a move.
Source
Thrown at apps/desktop/electron/main.ts:11767
ipcMain.handle('hermes:fs:desktopPluginsRoot', async () => localPluginsRoot('desktop-plugins'))
// The LOCAL agent-plugin root (`<HERMES_HOME>/plugins`), same Electron-local
// resolution as above. This is the desktop half of a UNIFIED plugin package:
// an agent plugin may ship `desktop/plugin.js` alongside its Python code (the
// same shape as `dashboard/manifest.json`), and the renderer's disk door scans
// this root for it — one installable folder serving both SDKs.
ipcMain.handle('hermes:fs:agentPluginsRoot', async () => localPluginsRoot('plugins'))
// Rename a file/folder in place. The renderer passes the existing path + a new
// base name; the destination is resolved in the SAME parent dir so a rename can
// never move the item elsewhere or traverse out. Rejects on a name collision.
ipcMain.handle('hermes:fs:rename', async (_event, targetPath, newName) => {
const src = String(targetPath || '').trim()
const name = String(newName || '').trim()
if (!src || !name || name === '.' || name === '..' || name.includes('/') || name.includes('\\')) {
throw new Error('Invalid rename')
}
const dst = path.join(path.dirname(src), name)
if (dst === src) {
return { path: dst }
}
if (fs.existsSync(dst)) {
throw new Error(`"${name}" already exists`)
}
await fs.promises.rename(src, dst)
return { path: dst }
})
// Write a small UTF-8 text file (e.g. a project's IDEA.md at creation). The pathView on GitHub (pinned to c896c09c42)
Solutions
- Trim and validate the new name client-side: non-empty, no '/' or '\\', not '.' or '..' before invoking the IPC
- Show inline validation in the rename UI instead of letting the IPC rejection surface
- If a move to another directory is the actual goal, use a different flow — this API intentionally cannot do it
Example fix
// before
await ipc.invoke('hermes:fs:rename', path, newName)
// after
const name = newName.trim()
if (!name || name === '.' || name === '..' || /[\\/]/.test(name)) return setRenameError('Enter a plain file name')
await ipc.invoke('hermes:fs:rename', path, name) Defensive patterns
Strategy: validation
Validate before calling
function isValidRename(name: string): boolean {
const n = name.trim()
return !!n && n !== '.' && n !== '..' && !n.includes('/') && !n.includes('\\')
}
if (!isValidRename(newName)) { setRenameError('Name must be a plain base name'); return }
await ipc.invoke('hermes:fs:rename', path, newName) Type guard
function isValidNewBaseName(name: unknown): name is string {
return typeof name === 'string' && name.trim().length > 0 && name.trim() !== '.' && name.trim() !== '..' && !/[\\/]/.test(name.trim())
} Try / catch
catch (e) { if (e instanceof Error && e.message === 'Invalid rename') setRenameError('Use a plain name without slashes') else throw e } Prevention
- Validate the rename field client-side with the same rules (no separators, no dot names)
- Disable submit while the rename input is empty
- Remember this API renames in place — use a different mechanism for moves
When it happens
Trigger: Renderer passes an empty path or empty new name, or a new name containing path separators (e.g. 'sub/dir', '..\\evil'), '.', or '..' — typically from an unsanitized inline-rename input.
Common situations: Rename field submitted while empty; user types a slash intending a nested move; copy-paste of a full path into the rename box.
Related errors
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/5bf968ce4a45447f.
Report an issue: GitHub.