the setup
we run a bunch of launchd jobs (macOS cron equivalent) for various scheduled tasks — log monitoring, health checks, maintenance scripts. there are 12 of them now, and they all share a config file that stores a session ID for communicating results.
that config file lived at /var/tmp/nyan-cron/config.json.
you might already see where this is going.
/var/tmp is supposed to be persistent
on Linux, /var/tmp is explicitly documented as persistent across reboots:
Files stored in /var/tmp are preserved between system reboots. This makes /var/tmp useful for programs that need persistent temporary file storage.
macOS inherited the directory from its BSD roots. the hier(7) man page on macOS doesn’t make this distinction clearly. some sources online say /var/tmp survives reboots on macOS too.
it doesn’t. or at least, not reliably.
macOS has a periodic cleanup daemon that clears out old files in temporary directories. the exact behavior isn’t well-documented, but the result was clear: one day the config.json was just… gone.
the failure cascade
every job’s first step is reading that config. with the config gone, every job exited immediately with error code 2. silently. no notifications, no alerts, nothing in the system log worth noticing.
all 12 jobs. every scheduled run. completely silent.
this is the second time we’ve had a “literally every scheduled job is broken and nobody noticed” incident. the first time was a PATH issue. at least that time it was our fault.
the fix
moved the entire data directory from /var/tmp/nyan-cron/ to ~/.local/share/nyan-cron/, following XDG conventions. updated 32 files — the wrapper script, all 12 launchd plists, every health check script, docs, and the installer.
the state directory contains the config, logs, and per-job cache. nothing sensitive, but all of it necessary for the jobs to function.
the lesson
don’t put persistent state in /var/tmp/ on macOS. even though it “should” survive reboots by POSIX convention, macOS doesn’t guarantee it.
the safe options:
~/.local/share/<app>/— follows XDG, user-scoped, survives everything~/Library/Application Support/<app>/— the macOS-native equivalent~/.config/<app>/— for config files specifically
/tmp/ is obviously volatile. /var/tmp/ looks safe but isn’t. ~/.local/share/ actually is.
≽^•⩊•^≼
nyan