The power went out this morning. Everything came back — server up, network up, dashboards loading, no alarms anywhere.

Except the speakers didn’t work. Then the Apple TV wasn’t there. Then I looked properly and found 840 entities sitting at unavailable, sixty-eight of them Sonos alone, plus the streaming boxes and the lighting system. A third of the house had quietly stopped existing, and nothing had told me.

I’d seen this once before, back in January, right after migrating to the new server. I fixed it then. It came back because the fix was the wrong shape.

Two services, one port

Home Assistant discovers a lot of the house over mDNS — the protocol that lets devices announce themselves on a local network. Sonos, Apple TV, Roku, and a pile of other integrations all depend on it. When Home Assistant runs with host networking, it binds the standard mDNS port directly.

The NAS operating system underneath also ships a discovery daemon, which wants that exact port for .local hostname resolution. Two services, one port, and the loser gets a startup error that reads, in its entirety, like this:

OSError: [Errno 98] Address in use

That’s it. That’s the whole event.

Whichever process gets there first wins, and after a clean boot the operating system’s own daemon is up long before a container has finished starting. So Home Assistant loses the race, logs one line into a file nobody is reading, and comes up perfectly healthy in every respect except that it can no longer find a third of the house.

That’s the part worth dwelling on. The service isn’t down. The dashboard loads. Automations run. Nothing pages you, because from the outside the system looks completely fine — it has simply lost the ability to see a category of device, and entities that were discovered by that mechanism drift to unavailable one by one over the following minutes. There is no alert for “a discovery protocol didn’t bind,” because at the moment of failure nothing is broken yet. It only becomes visible later, as an absence.

Why it comes back

The January fix was the obvious one: stop the daemon, disable the daemon, restart the container. It worked immediately and it held for months, which is exactly how long it takes to forget that you did it.

The problem is that a disabled service is a piece of state, and on an appliance OS you don’t own that state.

A NAS distribution isn’t a general-purpose Linux box that happens to have a web interface. It’s a system that manages its own service configuration and reconciles it toward what its own config says on every boot. My disable wasn’t a durable decision; it was a local edit to something the platform believes it owns, and on the next boot the platform put it back the way it thinks it should be. Not maliciously. Not even as a bug, really — it’s doing the thing it was built to do.

Which means the mental model I was using was wrong. I thought I had changed a setting. What I had actually done was win an argument once, with something that reopens the argument every time it starts.

Two power cycles, two identical outages, and the second one had to teach me the same thing again because the first one had let me believe a one-time change was a fix.

Deliberately losing the race

The durable answer isn’t a better config change. It’s accepting that the daemon will start, and killing it after it does.

A boot-time job now waits thirty seconds, then stops and disables the daemon. That delay is the trick, and it’s counterintuitive enough to be worth spelling out: I’m not trying to beat the operating system to the port. I’d lose that race, because the platform’s own services start well before anything I schedule, and racing a system service from a user job is how you get a fix that works four times out of five.

So I concede the first race on purpose and win the rematch. Let the OS start its daemon. Let the boot settle. Then take the port away and let the container’s own restart policy pick it up on the retry it was already going to make.

The shape of the fix generalizes past this one daemon: on a system that reconciles its own state, don’t make a change — install a reconciler of your own. Anything you configure outside the appliance’s management model should be assumed reverted on every boot, and the durable version of that decision is a thing that runs and re-asserts it, not a setting you flip and remember fondly.

The trade-off here is real but small: with that daemon disabled, the NAS itself no longer answers to .local names. I address it directly instead, which costs me nothing, because a hostname I type twice a month is worth less than a third of the house being discoverable.

There were more elegant options and I rejected all of them. Give Home Assistant its own network interface so nothing collides — genuinely correct, meaningfully more complex, and a bigger change than the problem deserves. Point Home Assistant at the system daemon instead of its own — not supported. Move Home Assistant to a separate machine — solves it completely, and now I own another machine.

The weakest joint

Here’s the thing I want on the record, because it’s the weakest joint in this whole arrangement.

The reconciler lives in a user-level scheduled job on the same operating system that has already demonstrated, twice, that it will reassert its own defaults over my preferences. I have fixed the daemon problem with a mechanism that lives inside the blast radius of the daemon problem. A platform update or a profile reset that tidies up user configuration would take the fix with it, silently, and I would find out the way I found out today — by noticing the music doesn’t work.

So verification is now part of the procedure rather than an afterthought. After any reboot: confirm the daemon is actually inactive, check the container’s log for that one error string, and spot-check that a couple of discovered devices are alive. Three commands, thirty seconds.

That feels excessive right up until you consider what the alternative has cost so far, which is two outages that were invisible until a person noticed something missing.

A mitigation you can’t verify isn’t a mitigation. It’s a belief about your system, and this failure mode specializes in making beliefs feel true right up until the power blinks.