Mac Local LLM OOM: Disk Full, APFS Postmortem and Guardrails

I run a small fleet of local agents on a Mac Mini M4 with 24 GB of unified memory. In the incident reported here, the machine would not boot and an APFS volume refused to mount in recovery mode. A background local model workload and a nearly full disk were part of the incident history. Recovery took more than a day. This is a personal failure report and a startup-control example, not a demonstrated mechanism by which an LLM corrupts APFS.

← hexisteme · notes · 2026-07-10

AI-assisted revision, reviewed and approved by the author. Reported experiences and example policies are not new measurements.

Evidence boundary: the author reports background 14B/8B model loading, low disk headroom, an unmountable APFS volume, and a prolonged recovery. No public diagnostic trace establishes the link from failed swap writes to metadata damage. The code change below targets unwanted model startup; it does not prove prevention of filesystem corruption. The local model path remains disabled.

The timeline: from "a little slow" to "won't boot"

It didn't look like a memory problem — just the machine getting sludgy: beachballs, slow app switching, the stuff you blame on too many tabs. Then the display went black, gone. A forced restart got the Apple logo and a progress bar that stalled and stayed. In recovery mode the shape came clear: Disk Utility saw the container, the data volume wouldn't mount, and the repair pass — fsck_apfs — hit metadata it couldn't reconcile, a volume whose own consistency layer had lost consistency. Repair couldn't finish, and the fix cost the better part of a day between attempts and a restore.

The proposed chain, and the missing evidence

The original explanation combined incident recollection with an inferred mechanism. Those are different kinds of evidence:

Apple's Activity Monitor guide explains memory pressure and startup-disk swap. Its archived APFS guide describes filesystem protection features; it is background documentation, not a diagnosis of this machine. To establish the proposed cause, the report would need contemporaneous memory/swap, disk/I/O, and filesystem diagnostics that exclude alternative causes. Those traces are not supplied here. Disk headroom is still a useful operating precaution without claiming a proven corruption mechanism.

Why a note in the config was never going to hold

The startup-control problem is narrower than the corruption hypothesis: a background path could start a model I did not want running. Written guidance alone did not enforce that decision. A caller or startup script can ignore a note, so the live entry points needed to refuse the unwanted startup. This addresses a controllable software path even while the filesystem failure's cause remains unresolved.

The fix: make the dangerous path refuse to run

So I replaced guidance with refusal, at every layer that could start the server — defense in depth, independent blocks, each alone enough to stop the process. Across the two repositories that could spawn the model:

_MLX_ENABLED = False              # one source of truth; every layer reads it

def _check_local_server_health() -> bool:
    return False                  # router has no branch that selects local

if __name__ == "__main__":        # executor: escalate & exit before the
    print(json.dumps({"escalate": True}))   # heavy import or any socket
    sys.exit(0)

def cmd_start(*args):             # CLI start refuses...
    raise SystemExit("local model server disabled — explicit change review required")

def _LEGACY_cmd_start(*args):     # ...original kept intact, out of the call graph
    ...                           # `nohup mlx_lm.server ...`

Each example is a positive refusal: the entry point runs and declines before loading the model. Keeping legacy code is an inspection aid, not evidence that changing a constant or renaming a function would be safe. These snippets illustrate the design; they are not a standalone package or an independently reproduced incident test.

Keep the disabled decision auditable

The historical write-up included a reactivation checklist. That is not the current operating instruction: the local model path remains disabled. What should survive in a change record is:

  1. The incident symptoms and the limits of the available diagnostics.
  2. The entry points that refuse startup and the callers they cover.
  3. Tests that show refusal occurs before heavy imports or spawning.
  4. The owner of any future authorized change and the separate review it would require.

This records why the block exists without offering instructions to reactivate it or claiming that it prevents all machine failures.

The rule the whole thing taught: disk free space is a memory safety net

The practical lesson is to budget concurrent workloads rather than treating a model's size as the machine's total demand. On this 24 GB machine, the OS, applications, and local workloads compete for resources. Activity Monitor's memory-pressure and swap indicators are more informative than model size alone.

Swap uses disk storage, so free disk space also matters to memory management. My historical 20 GB disk floor was a precaution, not a measured boundary between a recoverable crash and filesystem damage. The operating rules recorded at the time were:

A later incident: comparison, not a controlled experiment

A later incident involved a reported 13.7 GB image workflow while Photoshop, a video editor, and a VM were open. The machine blacked out, but booted after a restart. This was a different workload, not a repetition with all variables controlled.

The author reported about 55 GB of disk headroom and a much shorter recovery. That is compatible with disk headroom helping, but it does not isolate disk capacity as the cause of the different outcome. No matched swap-write trace is supplied for the two events. The comparison below summarizes recollections, not instrumented measurements.

Dimension2026-04-212026-07-03
What overcommittedBackground LLM: 14B + 8B modelsImage workflow 13.7 GB + Photoshop + video editor + VM
Memory stateMemory pressure inferred from workload and symptomsMemory pressure inferred from overlapping workloads
Free disk at the timeNearly none~55 GB
Swap-write traceNot suppliedNot supplied
ResultAPFS metadata corrupt, unbootableBlackout, clean reboot
Recovery24+ hoursA few minutes

The two outcomes motivated stricter workload budgeting, not a claim that disk headroom guarantees a clean reboot. The specific startup block and the operational precautions solve different problems. Evidence of another cause would overturn the proposed corruption chain; tests finding another live startup entry point would show that the block's coverage needs repair.

FAQ

Can a local LLM running out of memory corrupt your filesystem?

This report does not establish that causal link. Memory pressure, a nearly full disk, and an unmountable APFS volume occurred in the reported incident, but there is no published trace proving that failed swap writes caused the metadata damage. Treat that chain as a hypothesis, not a general property of APFS.

Why does disk headroom matter during memory pressure on a Mac?

Apple documents swap as startup-disk storage used for memory management. Disk capacity therefore matters when swap is needed. The 20 GB floor in this report is a personal operating guardrail, not an Apple safety guarantee or a demonstrated threshold for preventing APFS damage.

Why replace a do-not-run note with code that refuses to start?

A runtime refusal blocks an unwanted startup even when a separate script or caller ignores written guidance. The example exits before loading the model library and makes the startup command decline. It addresses that startup path, not every source of memory pressure or filesystem failure.

What does preserving disabled code mean here?

Legacy code is retained for inspection and change review, not as permission to activate it. The local model path remains disabled. Any future change would need its own explicit authorization, call-path review, resource checks, and tests; this article does not provide a reactivation procedure.

What can a 24 GB Mac owner take from this incident?

Avoid overlapping heavy workloads, observe memory pressure and swap in Activity Monitor, retain disk headroom, and keep recoverable backups. These are operating precautions, not a guarantee against crashes or APFS damage. The historical resource floors in this report have not been validated as universal limits.

Related notes

Want more failure-analysis notes? Nothing here requires signup. I write about agent-fleet operations, harness bugs, and validation records, including their limits. This incident's corruption mechanism remains unresolved. Get new notes by email.
← hexisteme · notes · about · editorial policy · privacy · contact · CC-BY 4.0