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

  1. Fix the caller to always pass at least one non-empty path component
  2. If whole-file removal is genuinely intended, delete/truncate the file explicitly instead of using the path-removal API
  3. Validate paths before calling: reject empty sequences and components derived from empty strings
  4. 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

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


AI-assisted analysis of tirth8205/code-review-graph@b58668751a (2026-08-28). Data as JSON: /api/errors/251a70c2aa79914b. Report an issue: GitHub.