◉CLAUDE LABJP
●THREADS — Message threads arrived in beta on the Messages API (11/2): the server keeps the conversation and you send only new messages●API — The Messages API maximum request size grew from 32 MB to 128 MB (10/28)●SONNET 4.5 — Retires on the Claude API on 11/30, 27 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST — Opus 4.8 fast mode is deprecated and will be removed on 11/30. Migrate to Opus 5.5●NEW — I Put a Ten-Line Promise File at the To…●THREADS — Message threads arrived in beta on the Messages API (11/2): the server keeps the conversation and you send only new messages●API — The Messages API maximum request size grew from 32 MB to 128 MB (10/28)●SONNET 4.5 — Retires on the Claude API on 11/30, 27 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST — Opus 4.8 fast mode is deprecated and will be removed on 11/30. Migrate to Opus 5.5●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-11-03Intermediate

When Claude Code dies with a Bus error on a shared home directory, check this before you turn off auto-update

Why Claude Code crashes with a Bus error on an NFS-style shared home, how the official cleanup rule and update switches work, and two small scripts to check your setup.

claude-code133auto-updatetroubleshooting103nfsinstallation3

I was rereading the setup page one evening when a small section called "Install on network storage" stopped me. It describes a session that crashes with a Bus error in the middle of work.

My own setup is a single iMac at home, with no shared home directory. So I haven't hit this myself. Still, for anyone whose home lives on network storage and is mounted on several machines, it's the kind of trouble that arrives without warning. I'm writing down the official notes in a form you can run.

The short version

What I'd like to say first: the crash happens because the file a session is running gets removed from another machine, so what you need to stop is every update path, plus the habit of deleting old versions by hand.

My first misreading was that DISABLE_AUTOUPDATER would be enough. The docs say plainly that it isn't.

The symptom and why it happens

A running Claude Code reads parts of its executable from disk while it works, not only at startup. If that file is truncated or deleted and becomes unreadable, the session crashes. In a Linux shell it shows up as Bus error.

When the home directory is on network storage, an update on one machine can remove the file under a session running on another. A machine can't see processes on other machines, so "check for running processes before deleting" doesn't work either.

Two ways the file disappears

I split the docs' explanation into two paths.

pathwhat happens
npm global upgrade`npm install -g` deletes the previous binary in place. On shared storage, that removes the version other machines are still running.
Native installer cleanupIt removes old versions under `~/.local/share/claude/versions/`. It keeps the version the launcher points to, any version running on the same machine, and the two newest versions, and deletes the rest.

The native cleanup only looks at its own machine. A session on another machine that is running an older version isn't protected.

Three levels of turning updates off

The settings differ in how far they reach.

settingstopsdoes not stop
`DISABLE_AUTOUPDATER`The background update check`claude update`, `claude install`
`DISABLE_UPDATES`Every update path, manual ones includedNothing (installs through your own tooling are separate)

For shared storage the docs point to DISABLE_UPDATES. If even one person types the command, DISABLE_AUTOUPDATER alone lets the same thing happen.

Stop more than "automatic": stop every update that anyone can trigger by hand. That's the line I'd draw.

Where to put things

The docs' layout advice comes down to three points.

  • Put the binary on each machine's local disk, for example through a Linux package manager or your own deployment tooling. The native installer's default ~/.local/share/claude/versions/ and a per-user npm prefix both sit in the home directory.
  • Keep each version in its own directory, and install new versions next to the old ones instead of overwriting.
  • Delete an old version only when you can say no machine is running it.

Two scripts I ran

The first checks whether the install location is on shared storage. It reads /proc/mounts and picks the mount that contains the path.

"""Check whether the Claude Code install location sits on shared storage (Linux)."""
import os
import sys
 
SHARED = {"nfs", "nfs4", "cifs", "smb3", "smbfs", "fuse.sshfs", "afs", "ceph", "glusterfs"}
 
 
def mount_of(path):
    path = os.path.realpath(path)
    best = ("/", "unknown")
    with open("/proc/mounts") as f:
        for line in f:
            _, mp, fstype, *_ = line.split()
            if (path == mp or path.startswith(mp.rstrip("/") + "/")) and len(mp) >= len(best[0]):
                best = (mp, fstype)
    return best
 
 
target = os.path.expanduser(sys.argv[1] if len(sys.argv) > 1 else "~/.local/share/claude")
probe = target
while not os.path.exists(probe) and probe != "/":
    probe = os.path.dirname(probe)          # if it does not exist yet, judge by the nearest existing parent
mp, fstype = mount_of(probe)
verdict = "shared storage: move the binary to local disk" if fstype in SHARED else "treated as local"
print(f"target={target}\nprobed={probe}\nmount={mp}  type={fstype}\n=> {verdict}")

In my Linux work environment the type came back as ext4, so the verdict was "local." If the path doesn't exist yet, it judges by the nearest existing parent. I haven't tried it on real shared storage, so I'd be glad if you could run it once in your own environment.

The second copies the official cleanup rule so you can see which versions survive. The version numbers are examples.

"""The documented cleanup rule: keep the launcher target, versions running on this machine, and the two newest."""
 
def key(v): return tuple(int(x) for x in v.split("."))
 
def survivors(installed, launcher_target, running_here):
    newest_two = sorted(installed, key=key)[-2:]
    return set(newest_two) | {launcher_target} | set(running_here)
 
installed = ["2.1.309", "2.1.313", "2.1.314", "2.1.316", "2.1.317"]   # 例
keep = survivors(installed, launcher_target="2.1.317", running_here=["2.1.317"])
deleted = [v for v in installed if v not in keep]
print("survive:", sorted(keep, key=key))
print("deleted:", deleted)
for host, ver in {"machine B": "2.1.309", "machine C": "2.1.316"}.items():
    print(f"{host} running {ver}:", "loses its binary" if ver in deleted else "fine")

This is what it printed.

survive: ['2.1.316', '2.1.317']
deleted: ['2.1.309', '2.1.313', '2.1.314']
machine B running 2.1.309: loses its binary
machine C running 2.1.316: fine

This is a calculation that mirrors the docs' wording, not a reproduction of real deletion. Even so, seeing the numbers made it obvious that "keep the two newest" doesn't protect a machine still running an older version.

What I check on a single machine

As an indie developer working on one iMac, I'd have filed the shared-home story under someone else's problem. Rereading it, though, I realized the way to confirm an update switch is the same everywhere.

After setting it, run claude doctor and look at the Auto-updates line. If it still says enabled, the setting isn't doing its job. Per the docs, when DISABLE_AUTOUPDATER is in effect it reads disabled (set by env: DISABLE_AUTOUPDATER). I used to stop at writing the settings file and never looked at that line. In hindsight, having written the setting and having it take effect were two different things.

What to do next

As a first step, run the location check on one of the machines that share the home directory. If it reports shared storage, move the binary to local disk, set DISABLE_UPDATES, and switch to updating through your own deployment. That single change takes away the morning when a crashed session's work doesn't come back.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

⟐ Claude Code2026-05-24
When Claude Code's Sequential Edits Cascade into Failure — Fixing 'old_string not found' and 'not unique' on the Same File
Run several Edits against the same file and the second or third one suddenly fails with 'not found', 'not unique' or 'modified since read'. Here is how to tell the three apart, a small script that counts matches first, and the correct formatter hook setup.
⟐ Claude Code2026-05-10
When Claude Code's Read Doesn't Reach the End of a File — Catching the PARTIAL view Notice and Sizing offset/limit
When Read returns only part of a large file, Claude Code says so with a PARTIAL view notice. Here is how to catch it, and how to size offset and limit by byte budget rather than line count, with measurements from my own sandbox.
⟐ Claude Code2026-05-10
Why Claude Code's Glob and Grep Return Zero Results
When Claude Code's Glob or Grep returns zero matches for files you can see, work through four boxes in order: ignore rules, hidden folders, pattern syntax, and the workspace boundary. Check the facts in your terminal first, then add one line to your opening prompt.