tirth8205/code-review-graph · error · ValueError
refusing to remove the JSON document root
Error message
refusing to remove the JSON document root
What it means
Raised by _removal_ranges as a safety check: the requested removal path is empty, which would target the entire JSON document root. Deleting the root is almost never the intent of a surgical key-removal tool, so it refuses with this error instead of wiping the file's whole JSON content.
Source
Thrown at code_review_graph/uninstall.py:336
if isinstance(component, str):
member = next(
(item for item in _object_members(tokens, current) if item.key == component),
None,
)
if member is None:
raise KeyError(component)
current = member.value_index
else:
elements = _array_elements(tokens, current)
if component < 0 or component >= len(elements):
raise IndexError(component)
current = elements[component].value_index
return current
def _removal_ranges(tokens: Sequence[_Token], path: Sequence[str | int]) -> list[tuple[int, int]]:
if not path:
raise ValueError("refusing to remove the JSON document root")
parent_index = _find_value(tokens, path[:-1])
component = path[-1]
if isinstance(component, str):
members = _object_members(tokens, parent_index)
sibling_index = next(
(index for index, member in enumerate(members) if member.key == component),
None,
)
if sibling_index is None:
raise KeyError(component)
item = members[sibling_index]
start = tokens[item.key_index].start
end = tokens[item.value_end - 1].end
if item.comma_index is not None:
return [(start, tokens[item.comma_index].end)]
if sibling_index > 0:
previous = members[sibling_index - 1]
if previous.comma_index is not None:View on GitHub (pinned to b58668751a)
Solutions
- Fix the caller to always pass at least one non-empty path component
- If whole-file removal is genuinely intended, delete/truncate the file explicitly instead of using the path-removal API
- Validate paths before calling: reject empty sequences and components derived from empty strings
- Add a unit test asserting the uninstall path list is never empty
Example fix
# before
_remove_jsonc_paths(text, paths=[()]) # -> refusing to remove the JSON document root
# after
paths = [p for p in paths if p]
if not paths:
raise ValueError("no removable paths specified")
_remove_jsonc_paths(text, paths=paths) Defensive patterns
Strategy: validation
Validate before calling
def valid_removal_paths(paths) -> bool:
return bool(paths) and all(isinstance(p, (list, tuple)) and len(p) > 0 for p in paths) Type guard
def is_nonempty_path(p) -> bool:
return isinstance(p, (list, tuple)) and len(p) > 0 and all(c != '' for c in p) Try / catch
try:
_remove_jsonc_paths(text, paths)
except ValueError as e:
if 'document root' in str(e):
raise RuntimeError('bug: empty removal path generated') from e Prevention
- Filter empty paths before calling the API
- Never derive paths from ''.split() or empty user input without checking
- If whole-file removal is intended, delete the file directly instead
When it happens
Trigger: Calling _remove_jsonc_paths (or a wrapper) with an empty path list/tuple, e.g. paths=[()] or paths=[[]]. Also when path-building code computes zero components because of a config/key naming bug or empty string split (''.split('.') yields []).
Common situations: Caller builds paths dynamically from user input and receives an empty key; a default/empty server name is passed during uninstall; refactoring changed a path constant to an empty sequence.
Related errors
- expected JSON object
- expected JSON array
- empty JSON document
- expected JSON object key
- expected colon after JSON object key
AI-assisted analysis of tirth8205/code-review-graph@b58668751a (2026-08-28).
Data as JSON: /api/errors/251a70c2aa79914b.
Report an issue: GitHub.