NousResearch/hermes-agent · error
Saving is not available
Error message
Saving is not available
What it means
Thrown by writeDesktopFileText() in apps/desktop/src/lib/desktop-fs.ts:91 when running in LOCAL mode (not remote FS mode) and the bridge object lacks a `writeTextFile` method. The hardened Electron IPC save path only exists in shells that expose it; an older desktop build, a stripped preload, or a non-desktop environment with a partial hermesDesktop stub reaches this guard and saving is refused rather than silently doing nothing.
Source
Thrown at apps/desktop/src/lib/desktop-fs.ts:91
export async function readDesktopFileText(path: string): Promise<HermesReadFileTextResult> {
if (!isDesktopFsRemoteMode()) {
return bridge().readFileText(path)
}
return remoteFsApi<HermesReadFileTextResult>(fsPath('read-text', path))
}
// Save UTF-8 text back to a file. Local writes go through the hardened Electron
// IPC; remote writes hit the dashboard's POST /api/fs/write-text (same path
// hardening, parent-must-exist, size cap) so the editor behaves identically in
// both modes. Stale-on-disk detection is the caller's job (re-read before save).
export async function writeDesktopFileText(path: string, content: string): Promise<{ path: string }> {
const desktop = bridge()
if (!isDesktopFsRemoteMode()) {
if (!desktop.writeTextFile) {
throw new Error('Saving is not available')
}
return desktop.writeTextFile(path, content)
}
const result = await remoteFsApi<{ ok?: boolean; path?: string }>('/api/fs/write-text', { content, path })
return { path: result.path || path }
}
export async function readDesktopFileDataUrl(path: string): Promise<string> {
if (!isDesktopFsRemoteMode()) {
return bridge().readFileDataUrl(path)
}
const result = await remoteFsApi<string | { dataUrl?: string }>(fsPath('read-data-url', path))
return typeof result === 'string' ? result : result.dataUrl || ''View on GitHub (pinned to c896c09c42)
Solutions
- Update the desktop shell so the preload exposes writeTextFile (restart the app after update — the hook's own copy recommends a restart for similar IPC gaps).
- Guard the save UI: disable the Save action when `!window.hermesDesktop?.writeTextFile && !isDesktopFsRemoteMode()`.
- In remote mode this path isn't taken — connect to the remote gateway so writes go through POST /api/fs/write-text.
- For tests, stub writeTextFile on the fake bridge.
Example fix
// before
await writeDesktopFileText(path, content) // throws on old shell
// after
const canSave = isDesktopFsRemoteMode() || Boolean(window.hermesDesktop?.writeTextFile)
if (!canSave) { setSaveUnavailable('Update the desktop app to enable saving'); return }
await writeDesktopFileText(path, content) Defensive patterns
Strategy: type-guard
Validate before calling
function canWriteFiles(): boolean {
return isDesktopFsRemoteMode() || typeof window.hermesDesktop?.writeTextFile === 'function'
} Type guard
function hasWriteTextFile(w: Window): w is Window & { hermesDesktop: { writeTextFile: (p: string, c: string) => Promise<unknown> } } {
return typeof (w as any).hermesDesktop?.writeTextFile === 'function'
} Try / catch
if (!canWriteFiles()) { setSaveDisabled('Update the desktop app to enable saving'); return }
try { await writeDesktopFileText(path, content) } catch (e) { notifyError(e, 'Save failed') } Prevention
- Bind the Save button's enabled state to the capability, not to view state
- Keep shell and renderer versions in lockstep (update + restart together)
- Remote mode routes writes through POST /api/fs/write-text — prefer it when bridging a remote backend
- Stub writeTextFile in bridge mocks
When it happens
Trigger: Calling writeDesktopFileText in local mode on an older Electron shell that predates the writeTextFile IPC; a test/mocked bridge exposing only `api`; a preview environment where the bridge exists but file-write capabilities were not injected.
Common situations: Desktop app and runtime on separate clocks after an update (renderer newer than shell); running the renderer in a browser with a partial hermesDesktop shim; sandboxed contexts where the write IPC was deliberately omitted.
Related errors
- Hermes Desktop bridge is unavailable
- Rename is not available
- Delete is not available
- Could not write artifact file
- Secure token storage is unavailable (no OS keyring service w
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/4e01d6c7e4402044.
Report an issue: GitHub.