tirth8205/code-review-graph · error · ValueError
expected JSON object
Error message
expected JSON object
What it means
Raised by _object_members when the token at the given index is not the '{' that opens a JSON object (or the index is past the end of the token stream). It means the JSONC path being edited assumes an object exists at that position, but the tokenizer found something else. This is part of the hand-rolled JSONC editing used to surgically remove keys from config files during uninstall.
Source
Thrown at code_review_graph/uninstall.py:271
index += 1
while index < len(tokens):
kind = tokens[index].kind
if kind == token.kind:
depth += 1
elif kind == closing:
depth -= 1
if depth == 0:
return index + 1
elif kind in ("{", "["):
index = _skip_value(tokens, index)
continue
index += 1
raise ValueError("unterminated JSON container")
def _object_members(tokens: Sequence[_Token], index: int) -> list[_Member]:
if index >= len(tokens) or tokens[index].kind != "{":
raise ValueError("expected JSON object")
members: list[_Member] = []
cursor = index + 1
while cursor < len(tokens) and tokens[cursor].kind != "}":
if tokens[cursor].kind == ",": # trailing comma
cursor += 1
continue
key_token = tokens[cursor]
if key_token.kind != "string" or not isinstance(key_token.value, str):
raise ValueError("expected JSON object key")
if cursor + 1 >= len(tokens) or tokens[cursor + 1].kind != ":":
raise ValueError("expected colon after JSON object key")
value_index = cursor + 2
value_end = _skip_value(tokens, value_index)
comma_index = value_end if (
value_end < len(tokens) and tokens[value_end].kind == ","
) else None
members.append(
_Member(key_token.value, cursor, value_index, value_end, comma_index)View on GitHub (pinned to b58668751a)
Solutions
- Validate the JSONC file parses as JSON (after stripping comments) before running the uninstall removal
- Check the path components: every intermediate component must address an object (str key) or array (int index) matching the actual document structure
- If the file was hand-edited, fix the unbalanced/missing braces so the target parent is actually an object
- Catch the ValueError and fall back to leaving the file untouched (or rewriting it wholesale) instead of crashing the uninstall
Example fix
# before
remove_jsonc_paths(text, ["mcpServers", "code-review-graph"])
# with {"mcpServers": "disabled"} -> ValueError: expected JSON object
# after
import json, re
def strip_comments(s):
return re.sub(r"//[^\n]*|/\*.*?\*/", "", s, flags=re.S)
try:
cfg = json.loads(strip_comments(text))
assert isinstance(cfg.get("mcpServers"), dict)
except (ValueError, AssertionError):
cfg = {}
remove_jsonc_paths(text, ["mcpServers", "code-review-graph"]) Defensive patterns
Strategy: validation
Validate before calling
import json, re
def strip_comments(s: str) -> str:
return re.sub(r"//[^\n]*|/\*.*?\*/", "", s, flags=re.S)
def parent_is_object(text: str, path: list) -> bool:
try:
doc = json.loads(strip_comments(text))
except ValueError:
return False
cur = doc
for c in path:
try:
cur = cur[c]
except (KeyError, IndexError, TypeError):
return False
return isinstance(cur, dict) Type guard
def is_json_object_root(text: str) -> bool:
t = text.lstrip()
return t.startswith('{') Try / catch
try:
_remove_jsonc_paths(text, paths)
except ValueError as e:
log.warning("skipping malformed config: %s", e) # leave file untouched Prevention
- Strip comments and json.loads the file before editing
- Keep intermediate path components type-correct (str for objects, int for arrays)
- Never hand-edit generated configs while an uninstall is in flight
When it happens
Trigger: Calling the uninstall/path-removal API with a path whose parent component resolves to a non-object value, e.g. removing 'a.b' when 'a' is a string, number, or array. Also triggered by malformed JSONC where an object is truncated or the wrong token lands at the expected position.
Common situations: User hand-edited a JSON config (settings.json, tsconfig-like file) and left it structurally broken; config schema changed between install and uninstall; path was built with a wrong key type (int where an object key was expected); comments/strings confused a hand-edit and braces got unbalanced.
Related errors
- expected JSON array
- empty JSON document
- refusing to remove the JSON document root
- 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/962d48ebab4bca46.
Report an issue: GitHub.