Home / Guides / Troubleshooting / Apple
macOS
Written by Jakub Rusinowski · Last updated September 1, 2026
Founder, LLM Configurator — AI educator & workshop leader on local LLM deployment
ggml_metal_init: recommendedMaxWorkingSetSize = 98304.00 MB
ggml_metal_init: skipping kernel_... (not supported)
ggml_backend_metal_buffer_type_alloc_buffer: error: failed to allocate buffer, size = 42000.00 MiB
| If you see | The cause is | Go to |
|---|---|---|
recommendedMaxWorkingSetSize is roughly 75% of your installed memory | That is the macOS default split — nothing is wrong yet | Fix 2: raise it if you have headroom to spare |
| A Metal buffer allocation fails just above that figure | The model wants more than the working-set ceiling permits | Fix 2, then confirm with Fix 3 |
| Memory Pressure is already yellow or red | You are short of memory, not short of ceiling | This is the swapping page, not this one |
sysctl iogpu.wired_limit_mb says "unknown oid" | Your macOS version uses the older debug.iogpu.wired_limit key | Fix 1: find which key your system accepts |
| You set it, rebooted, and it reverted | sysctl set at the command line does not persist | Fix 4: make it persistent deliberately |
You have plenty of memory and the loader disagrees. The line that gives it away is recommendedMaxWorkingSetSize in llama.cpp or Ollama's startup output, reporting a ceiling well below what the machine actually has installed.
Metal advertises a recommended maximum working-set size — the amount of unified memory it considers safe to hand the GPU — and llama.cpp, Ollama and most Metal-based runtimes treat that figure as a hard ceiling. macOS sets it conservatively, commonly around 75% of installed memory, reserving the rest for the system. On a 128 GB machine that means roughly 96 GB for the GPU, which is a lot in absolute terms and can still be just short of what a large model plus its KV cache wants. The iogpu.wired_limit_mb sysctl changes that split. It is an undocumented tunable: Apple does not publish it, its name has already changed once between macOS versions, and it can change again in any release.
Two keys have carried this setting. Current systems use iogpu.wired_limit_mb; older macOS versions used debug.iogpu.wired_limit. Reading them tells you which one exists on your machine — and this matters, because setting a key your system does not have appears to succeed and does nothing at all, which is how people conclude the tunable is a myth. A value of 0 means "use the system default", not "no limit".
# zsh — which key exists here?
sysctl iogpu.wired_limit_mb 2>/dev/null || echo "iogpu.wired_limit_mb: not present"
sysctl debug.iogpu.wired_limit 2>/dev/null || echo "debug.iogpu.wired_limit: not present"
# Total installed memory, in MB
sysctl -n hw.memsize | awk '{printf "%d MB installed\n", $1/1048576}'The value is in megabytes: 60 GB is 61440, 96 GB is 98304. Set it with sysctl and it takes effect immediately with no reboot. How much to leave is a judgement, and this table is our recommendation, not an Apple-documented value — the upstream guidance is simply that going near 100% is where things go badly wrong, with about 70% of physical RAM commonly cited as the safe ceiling. On a 32 GB Mac leave at least 8 GB for the system (set ~24576). On 64 GB, leave at least 10 GB (set ~55296). On 128 GB, leave at least 16 GB (set ~114688).
⚠️ Do not set this near 100% of installed memory. macOS needs memory it cannot page out, and starving it produces kernel panics and forced reboots — you lose whatever was unsaved, and the machine can panic again during recovery. Leave the headroom above.
# zsh — 60 GB ceiling on a 64 GB Mac; takes effect immediately, lost on reboot
sudo sysctl iogpu.wired_limit_mb=55296
# Read it back
sysctl iogpu.wired_limit_mbsysctl iogpu.wired_limit_mbSetting the sysctl is not the same as the runtime honouring it, and this is the check that closes the loop. Start a model and read the ggml_metal_init: recommendedMaxWorkingSetSize line in the loader output. If that number has not moved, either you set the key your system does not use, or the runtime was already running and cached the old value — restart it.
# zsh — llama.cpp prints it on every load
./llama-cli -m model.gguf -ngl 999 2>&1 | grep -i recommendedMax
# Ollama: restart the app, then read its log
log show --last 5m --predicate 'process CONTAINS "ollama"' 2>/dev/null | grep -i recommendedMax./llama-cli -m model.gguf -ngl 999 2>&1 | grep -i recommendedMaxA sysctl set at the command line is lost on reboot. Adding the key to /etc/sysctl.conf makes it permanent. There is a reasonable argument for not doing that: a value that suits a long inference session is not one you want in force while you are editing video or running a VM, and a per-session sudo sysctl keeps the change scoped to when you actually need it. If you do persist it, err generously on the headroom, because a bad value now applies to every boot.
⚠️ A too-aggressive persistent value applies at every boot, including the boot you use to fix it. Test with a live sysctl first and only persist a value you have run under load for a while.
# zsh — persist across reboots
echo "iogpu.wired_limit_mb=55296" | sudo tee -a /etc/sysctl.conf
# Or revert to the system default at any time (0 = default, not unlimited)
sudo sysctl iogpu.wired_limit_mb=0sysctl iogpu.wired_limit_mbUpstream's warning is blunt — things go seriously wrong if you do not leave enough space — and it is worth knowing what "seriously wrong" looks like so you recognise it as your own doing. The progression is: the system becomes sluggish under load; the window server stutters and applications are slow to redraw; then a kernel panic and a forced reboot, losing unsaved work. If you see any of the first two after raising the limit, lower it rather than pressing on.
# zsh — did the machine panic since you changed this?
ls -lt /Library/Logs/DiagnosticReports/*.panic 2>/dev/null | head -3
# Back off to the default while you reconsider
sudo sysctl iogpu.wired_limit_mb=0ls -lt /Library/Logs/DiagnosticReports/*.panic 2>/dev/null | head -3The most important sentence on this page: raising the limit changes the split, it does not add memory. If a model needs more than your Mac has, no value of this sysctl will help, and pushing the ceiling up on a machine that is already short simply moves the pain from a Metal allocation failure to swapping or a panic. It is also not a substitute for buying enough memory — on a 16 GB Mac the honest answer is a smaller model. Check what actually fits first; raise the ceiling only when the arithmetic says you are genuinely just short.
# zsh — installed, current ceiling, and what is left for macOS
sysctl -n hw.memsize | awk '{printf "installed: %d MB\n", $1/1048576}'
sysctl -n iogpu.wired_limit_mb 2>/dev/null | awk '{printf "gpu ceiling: %s MB\n", $1}'If Memory Pressure was already red before you touched any of this, the ceiling was never the constraint and the swapping page is the right one. If Metal is not being used at all, no ceiling change will help.
Include this when you report it
ggml_metal_init: recommendedMaxWorkingSetSize line from your loadersysctl iogpu.wired_limit_mb (or the debug key) and sysctl hw.memsizeHow much of unified memory Metal will let the GPU wire down, which runtimes read as recommendedMaxWorkingSetSize and treat as a hard ceiling. It redistributes existing memory between GPU and system; it does not add any.
Our recommendation is at least 8 GB on a 32 GB Mac, 10 GB on 64 GB and 16 GB on 128 GB. Upstream guidance is looser — do not go near 100%, with roughly 70% of physical RAM commonly cited as safe. These are judgements, not Apple-documented values.
No. A command-line sysctl is lost at reboot. Adding the key to /etc/sysctl.conf persists it. Many people prefer not to, so an aggressive value is only in force during the sessions where they actually need it.
Your macOS version uses the older debug.iogpu.wired_limit key instead. This matters because setting a key your system does not have looks like it worked and changes nothing — always read the value back and confirm the loader's reported working-set size moved.
The system becomes sluggish, the window server stutters, and eventually the machine kernel panics and reboots, losing unsaved work. macOS needs memory it cannot page out. If you see the first two symptoms after raising the limit, lower it.