fix config corruption when deleting the last commented mask or zone (#23627)
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
CI / AMD64 Extra Build (push) Blocked by required conditions

Deleting the last entry of a mapping or sequence via config/set orphaned ruamel's comment tokens, which were then emitted above a flow-style {} / [] at column 0, which is unparseable yaml that failed validation and silently rolled the change back. The fix is to clear the emptied collection's stale comment metadata (and the parent's entry for it) so the dump stays valid. Non-empty collections are left untouched so sibling comments are preserved. This covers both emptied maps and emptied lists.
This commit is contained in:
Josh Hawkins
2026-07-04 17:10:32 -06:00
committed by GitHub
parent 729ee86043
commit 1c745e0847
2 changed files with 208 additions and 0 deletions
+25
View File
@@ -293,26 +293,51 @@ def update_yaml_file_bulk(file_path: str, updates: Dict[str, Any]):
logger.error(f"Unable to write to Frigate config file {file_path}: {e}")
def clear_orphaned_comments(collection, parent, parent_key) -> None:
"""Drop stale ruamel comment tokens after a deletion empties a collection.
When the last entry of a mapping or sequence is removed, any comments that
lived inside that collection's block are orphaned. ruamel then emits them
above a flow-style `{}`/`[]` dedented to column 0, which is unparseable and
corrupts the config. Clearing the emptied collection's own comment metadata
(and the parent's entry pointing at it) keeps the dump valid. Non-empty
collections are left untouched so comments on remaining siblings survive.
"""
if not hasattr(collection, "ca") or len(collection) != 0:
return
collection.ca.items.clear()
collection.ca.comment = None
if parent is not None and hasattr(parent, "ca"):
parent.ca.items.pop(parent_key, None)
def update_yaml(data, key_path, new_value):
temp = data
parent = None
parent_key = None
for key in key_path[:-1]:
if isinstance(key, tuple):
if key[0] not in temp:
temp[key[0]] = [{}] * max(1, key[1] + 1)
elif len(temp[key[0]]) <= key[1]:
temp[key[0]] += [{}] * (key[1] - len(temp[key[0]]) + 1)
parent, parent_key = temp[key[0]], key[1]
temp = temp[key[0]][key[1]]
else:
if key not in temp or temp[key] is None:
temp[key] = {}
parent, parent_key = temp, key
temp = temp[key]
last_key = key_path[-1]
if new_value == "":
if isinstance(last_key, tuple):
del temp[last_key[0]][last_key[1]]
clear_orphaned_comments(temp[last_key[0]], temp, last_key[0])
else:
del temp[last_key]
clear_orphaned_comments(temp, parent, parent_key)
else:
if isinstance(last_key, tuple):
if last_key[0] not in temp: