[BUG] Claude Desktop linux-arm64: no local Claude Code session is ever persisted — bundled Electron 42.10.0 has wrong fcntl constants, every private-dir write fails with EINVAL
Preflight Checklist
- [X] I have searched existing issues and this hasn't been reported yet
- [X] This is a single bug report (please file separate reports for different bugs)
- [X] I am using the latest version of Claude Code
What's Wrong?
On Claude Desktop for Linux arm64, no local Claude Code session is ever persisted. Start a session, close the app, reopen it: the session is gone from the sidebar and its project group has disappeared.
The Claude Code transcripts themselves are fine — they are all in ~/.claude/projects/<slug>/*.jsonl. It is Claude Desktop's own session index that never gets written. ~/.config/Claude/claude-code-sessions/<account>/<org>/ stays empty forever.
It is not only sessions. Every private-directory write in the app fails the same way:
claude-code-sessions/<account>/<org>/ local Claude Code sessions
local-agent-mode-sessions/<account>/<org>/ agent-mode sessions
local-agent-mode-sessions/<account>/<org>/rpm
local-agent-mode-sessions/skills-plugin/<org>/<account>/skills
claude-code/2.1.246, claude-code/2.1.247 bundled CLI updater
claude-code/2.1.247/ was created but left empty, so the bundled CLI cannot self-update either. [CCDScheduledTasks] Failed to save scheduled tasks fails for the same reason.
The cause is the bundled Electron 42.10.0, whose linux-arm64 build reports the x86-64 fcntl constants. Filed upstream as electron/electron#53315. Reporting it here because it is this app that breaks for the user, and because there is a fix available to you immediately: Electron 43.4.1 is verified good on linux-arm64.
What Should Happen?
Local Claude Code sessions should be written to ~/.config/Claude/claude-code-sessions/<account>/<org>/ and restored on the next launch, in their project group.
Error Messages/Logs
# ~/.config/Claude/logs/main.log — 72 occurrences before patching
[error] Failed to save session local_<id>: EINVAL: invalid argument,
open '~/.config/Claude/claude-code-sessions/<account>/<org>'
at async open (node:internal/fs/promises)
at async $r (index.chunk-Cv8AY_mc.js)
at async ensureStorageDir (index.chunk-Cv8AY_mc.js)
at async writeSnapshotToDisk
[info] Loaded 0 persisted sessions from ~/.config/Claude/claude-code-sessions/<account>/<org>
[error] [CCDScheduledTasks] Failed to save scheduled tasks: EINVAL: invalid argument,
open '~/.config/Claude/claude-code-sessions/<account>/<org>'
Steps to Reproduce
- On Linux aarch64, install
claude-desktop1.40609.0 (official arm64.deb). - Open Claude Desktop, switch to Code, pick any folder, start a local Claude Code session and send one message.
- Observe
~/.config/Claude/claude-code-sessions/<account>/<org>/— it stays empty, andmain.loglogs theEINVALabove. - Quit and reopen the app.
The session is gone from the sidebar; main.log shows Loaded 0 persisted sessions.
This reproduces on every launch. It is not intermittent and it is not state-dependent — the write has never once succeeded on this machine.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.246 (bundled in Claude Desktop 1.40609.0); standalone CLI 2.1.251, which is unaffected
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
Debian forky/sid, Linux 7.2.2 aarch64 (Snapdragon X1P42100), ext4. Claude Desktop 1.40609.0 arm64, Electron 42.10.0 / Node 24.18.1.
Root cause. The private-directory helper calls:
open(dir, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0))
The bundled Electron reports the x86-64 values rather than the aarch64 ones:
| constant | reported | correct on aarch64 |
| --- | --- | --- |
| O_DIRECTORY | 65536 | 16384 |
| O_NOFOLLOW | 131072 | 32768 |
| O_DIRECT | 16384 | 65536 |
On aarch64 those bits mean O_DIRECT | O_LARGEFILE, and O_DIRECT on a directory returns EINVAL. Confirmed by flipping the runAsNode fuse on a copy of the shipped binary:
$ ELECTRON_RUN_AS_NODE=1 ./claude-desktop-copy probe.js
{"node":"24.18.1","electron":"42.10.0","arch":"arm64",
"O_DIRECTORY":65536,"O_NOFOLLOW":131072,"O_DIRECT":16384}
This is upstream Electron's bug, not yours: the untouched official electron-v42.10.0-linux-arm64.zip behaves identically. It affects every Electron linux-arm64 release published from 2026-08-24 on (42.10.0, 42.10.1, 44.0.0) across three branches, while everything up to 43.4.1 (2026-08-19) is fine — same Node 24.18.1 on both sides, so it is the arm64 build environment. Details in electron/electron#53315.
Security note. Your helper passes O_NOFOLLOW to guard against a symlink being planted at the private-dir path (Refusing non-directory at private dir path (symlink/file plant)). Under the wrong constants O_NOFOLLOW becomes O_LARGEFILE, a no-op on 64-bit — so on arm64 that defence is silently absent whenever the open() does succeed.
Confirmation. I patched app.asar locally, replacing every read of those three constants with the correct aarch64 literals (54 sites across 13 .js entries, same-length replacements so the asar header and offsets stay valid). After a restart:
EINVAL occurrences : 0
claude-code-sessions/<account>/<org>/
local_<id>.json 5910 bytes
scheduled-tasks.json 125 bytes
[info] Loaded 1 persisted sessions from …/claude-code-sessions/…
Nothing else changed.
Suggested fix. Ship the arm64 build on an Electron release predating the upstream regression — 43.4.1 is verified good — until upstream is fixed. A defensive alternative that costs nothing: derive those three flags from process.arch instead of trusting fs.constants, or drop O_DIRECTORY/O_NOFOLLOW from the flags and rely on the fstat().isDirectory() check you already perform right after the open().
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗