Analysis
How to Restore Home Assistant YAML Without Losing Live Changes

A Home Assistant YAML restore can be perfectly valid and still erase newer automations. The safe procedure is to treat the live file and the repository copy as two competing states: compare them structurally, preserve both, build the intended result forward from live, validate it, and only then restart.
\n
I caught this on September 12, 2026 while adding a local Qwen3 assistant. The AI configuration worked. The more useful lesson was that a restore tool can be technically correct and still restore the wrong point in time.
Why a configuration snapshot may not be authoritative
My Home Assistant role describes its own model plainly: Home Assistant is the source of truth; the repository is a read-only mirror plus disaster recovery. The routine synchronization runs from live /config into home-assistant/config. It does not continuously push Git back into the house.
That distinction is easy to forget because the repository also contains a separate restore.yml. The restore playbook accepts one relative filename, checks that it exists in the snapshot, copies the complete file to /config with Ansible’s backup option enabled, and can restart Home Assistant afterward.
The tool was doing exactly what its name promised. The dangerous assumption was mine: I had not proved that the snapshot was newer than the live file.
Start by proving that the two files represent the same intent
| File | Repository snapshot | Live Home Assistant | What a blind restore would do |
|---|---|---|---|
configuration.yaml |
Still contained an http: block |
HTTP settings had moved to the UI-backed .storage/http state on August 10 |
Resurrect an obsolete configuration block |
scripts.yaml |
826 lines | 1,038 lines | Replace the live file and lose roughly 212 lines |
Neither problem was a YAML syntax error. The old files could be perfectly valid YAML and still be the wrong files for the current system. That is why validation belongs after the content comparison, not instead of it.
Use a structural diff before reading line noise
The Windows working copy used CRLF line endings. The live files used LF. A normal diff reported nearly every line as changed, burying the actual configuration drift in formatting noise.
The comparison became useful when I told diff to ignore the trailing carriage return:
ssh home-assistant 'sudo cat /config/configuration.yaml' > /tmp/live.yaml
diff --strip-trailing-cr -u \
/tmp/live.yaml \
home-assistant/config/configuration.yaml
I repeated the comparison for scripts.yaml. The important output was not “different.” I needed to know which side contained each block, whether the change belonged in live state, and whether the snapshot had simply missed a later pull.
Line-ending normalization is not permission to ignore whitespace generally. YAML indentation is structure. I ignored only the known CRLF/LF transport difference so that indentation and content changes remained visible.
Build the desired file forward from live state
Once the drift was clear, I stopped treating the repository copy as the input. I fetched the two live files, added only the Ollama REST probe, availability sensor, command, and script blocks, and wrote those candidates back.
The Home Assistant SSH environment did not accept the ordinary file-copy path I was using, so the final transfer used standard input and sudo tee:
ssh home-assistant \
'sudo tee /config/configuration.yaml > /dev/null' \
< push-configuration.yaml
ssh home-assistant \
'sudo tee /config/scripts.yaml > /dev/null' \
< push-scripts.yaml
Those commands are intentionally incomplete as a copy-and-paste deployment recipe. They assume an authorized SSH alias and reviewed candidate files. They do not expose addresses, credentials, or keys from my network.
Create the rollback artifact before the write
The live files were copied to timestamped rollback names before the write: configuration.yaml.bak-20260912-220058 and scripts.yaml.bak-20260912-220058. Those local copies are excluded from the repository snapshot because they can contain old plaintext configuration and would create a second secret-handling problem.
A timestamped file beside the live configuration is useful for a small immediate rollback. It is not a complete Home Assistant backup. It omits UI-managed state, integration credentials, add-on data, media, and everything else outside those two files.
Home Assistant’s official backup documentation describes full and partial encrypted backups and recommends keeping another copy outside the Home Assistant device. That is the recovery path for a failed system or migration. My Git snapshot has a narrower job: inspectable YAML history and a controlled one-file recovery source.
ha core check is necessary, but it cannot detect stale intent
After writing both candidates, I ran:
ssh home-assistant 'bash -l -c "ha core check"'
The check passed. Home Assistant’s official Operating System documentation says the CLI check validates YAML, configuration structure, and additional configuration elements before a restart. I then restarted Core and verified the new Ollama entities and availability path.
That success proves the candidate was acceptable to Home Assistant. A clean check says nothing about stale repository state or whether every existing script still behaves the same way. The line-count and content diff answered a different question from the configuration validator.
A safe Home Assistant YAML restore sequence
- Pull the live target. Do not assume the repository won the most recent edit.
- Compare content after normalizing only known transport noise. On this workstation that meant CRLF versus LF.
- Explain every meaningful difference. A block can be valid, old, and dangerous at the same time.
- Build the candidate from the authoritative side. For this change, that was live Home Assistant plus the reviewed additions.
- Create a recoverable pre-write checkpoint. Know the exact file and command needed to reverse the change.
- Validate before restarting. Run
ha core check; do not use the restart as the syntax test. - Verify the feature and its neighbors. I checked the Ollama entities, availability gate, and script path rather than accepting “Core restarted” as the finish line.
- Refresh the snapshot afterward. Disaster recovery should capture the new known-good state, not preserve the near-miss forever.
Do not automate stale state into authority
I could declare the repository authoritative and force every Home Assistant edit through Git. That would make drift easier to reason about, but it would ignore the way this installation actually changes. Some settings live in the UI and .storage. Scripts can be edited in Home Assistant. Integrations migrate configuration between YAML and UI-backed state. A workflow that pretends those paths do not exist will eventually overwrite one of them.
The better improvement is to make direction explicit. Routine jobs may pull a sanitized snapshot. Restore jobs are exceptional, name one file, preserve the destination, and require a fresh comparison. If I later automate that comparison, it should fail closed when the live hash differs from the reviewed base.
Use the tools already in the restore path
This failure did not call for another backup appliance, deployment product, or Home Assistant subscription. The useful controls were already available: Git, SSH, diff, Ansible’s backup copy, the Home Assistant CLI, and Home Assistant’s built-in encrypted backups.
I would spend time proving that automatic backups complete and that a copy exists off the Home Assistant machine before buying another tool. A paid off-site destination can be reasonable, but this incident does not contain enough recovery-time, storage-size, or restore-test evidence to choose one.
What the example changed
The official Home Assistant documentation supports the current behavior of configuration validation and built-in backups. Product-specific claims about my snapshot and restore path come from the repository source and change record.