{"record":{"id":"5bf968ce4a45447f","repo":"NousResearch/hermes-agent","slug":"invalid-rename","errorCode":null,"errorMessage":"Invalid rename","messagePattern":"Invalid rename","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/desktop/electron/main.ts","lineNumber":11767,"sourceCode":"\nipcMain.handle('hermes:fs:desktopPluginsRoot', async () => localPluginsRoot('desktop-plugins'))\n\n// The LOCAL agent-plugin root (`<HERMES_HOME>/plugins`), same Electron-local\n// resolution as above. This is the desktop half of a UNIFIED plugin package:\n// an agent plugin may ship `desktop/plugin.js` alongside its Python code (the\n// same shape as `dashboard/manifest.json`), and the renderer's disk door scans\n// this root for it — one installable folder serving both SDKs.\nipcMain.handle('hermes:fs:agentPluginsRoot', async () => localPluginsRoot('plugins'))\n\n// Rename a file/folder in place. The renderer passes the existing path + a new\n// base name; the destination is resolved in the SAME parent dir so a rename can\n// never move the item elsewhere or traverse out. Rejects on a name collision.\nipcMain.handle('hermes:fs:rename', async (_event, targetPath, newName) => {\n  const src = String(targetPath || '').trim()\n  const name = String(newName || '').trim()\n\n  if (!src || !name || name === '.' || name === '..' || name.includes('/') || name.includes('\\\\')) {\n    throw new Error('Invalid rename')\n  }\n\n  const dst = path.join(path.dirname(src), name)\n\n  if (dst === src) {\n    return { path: dst }\n  }\n\n  if (fs.existsSync(dst)) {\n    throw new Error(`\"${name}\" already exists`)\n  }\n\n  await fs.promises.rename(src, dst)\n\n  return { path: dst }\n})\n\n// Write a small UTF-8 text file (e.g. a project's IDEA.md at creation). The path","sourceCodeStart":11749,"sourceCodeEnd":11785,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/electron/main.ts#L11749-L11785","documentation":"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.","triggerScenarios":"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.","commonSituations":"Rename field submitted while empty; user types a slash intending a nested move; copy-paste of a full path into the rename box.","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"],"exampleFix":"// before\nawait ipc.invoke('hermes:fs:rename', path, newName)\n\n// after\nconst name = newName.trim()\nif (!name || name === '.' || name === '..' || /[\\\\/]/.test(name)) return setRenameError('Enter a plain file name')\nawait ipc.invoke('hermes:fs:rename', path, name)","handlingStrategy":"validation","validationCode":"function isValidRename(name: string): boolean {\n  const n = name.trim()\n  return !!n && n !== '.' && n !== '..' && !n.includes('/') && !n.includes('\\\\')\n}\nif (!isValidRename(newName)) { setRenameError('Name must be a plain base name'); return }\nawait ipc.invoke('hermes:fs:rename', path, newName)","typeGuard":"function isValidNewBaseName(name: unknown): name is string {\n  return typeof name === 'string' && name.trim().length > 0 && name.trim() !== '.' && name.trim() !== '..' && !/[\\\\/]/.test(name.trim())\n}","tryCatchPattern":"catch (e) { if (e instanceof Error && e.message === 'Invalid rename') setRenameError('Use a plain name without slashes') else throw e }","preventionTips":["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"],"tags":["validation","filesystem","ipc","desktop","rename"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}