My automation ate my music library, then blamed the NAS

My automation ate my music library, then blamed the NAS

After the NAS lost a volume, I asked the assistant to put my playlists back. It came back a while later with news I did not expect: the playlists were not the NAS’s fault, they were mine. Well — ours. The cron job’s.

Two of the three playlists were fine. The third was 316 bytes of track stubs with no file paths in them. Names, positions, no files. The kind of file that opens without error, lists its tracks, and plays nothing.

The obvious suspect was the storage failure everything else had come from. It was not. A nightly “Movie Themes” job had been rebuilding that playlist from a manifest on the NAS, and when the NAS became unreachable the job kept running. Night after night. Each run read nothing, wrote a fresh file from nothing, and reported success, because from its point of view it had done exactly what it was asked: produce the playlist file. It never asked whether the input existed, and it never compared what it wrote against what had been there.

That is the failure mode worth the whole post: an automation whose input disappeared and which kept writing anyway. It did not crash. It did not error. It did not alert. It quietly replaced a real thing with the shape of a real thing, and it would have kept doing it for as long as the schedule held.

The forensics came before the rebuild, which is the only reason the story has an ending rather than a repeat. Where did the tracks come from originally, which ones were still reachable, what did the file look like the last time it was correct. Once that was on the table the rebuild was mechanical: eight Sonos-native playlists, 386 tracks, pulled back from YouTube Music with yt-dlp.

One track was genuinely gone — the video deleted, unavailable, the original upload pulled. Substituted with the same recording from the artist’s official channel, which is the honest version: same audio, different host, and I would rather have the song than a gap and a note explaining the gap.

Then every playlist was verified by playing it. At volume zero, one track at a time, checking that something reported PLAYING rather than skipping or erroring. Verification at volume zero is a strange thing to do at the end of a rebuild and it is the only check that tells you the file is real instead of merely well-formed. 386 tracks that exist on disk and are not referenced by anything look identical to 386 tracks that work, right up until you press play.

The job is deleted. That was the actual fix. Everything else was repair.

What I keep thinking about is how reasonable it looked. A schedule, a source, a target, a nightly rebuild — the design is unremarkable and it is the design most of us would write. The missing piece was one line of judgement: if the source cannot be read, do not write the target. If the new file is a fraction of the size of the old one, do not replace the old one. Cheap checks, and the difference between an automation that maintains something and an automation that slowly eats it.