Graphify-Labs/graphify · error · ValueError
label response is not parseable JSON: {text[:120]!r}
Error message
label response is not parseable JSON: {text[:120]!r} What it means
ValueError raised when a community-label batch response from the LLM is neither parseable JSON nor salvageable by the regex fallback. The parser first tries full JSON; on failure it recovers complete quoted cid/name pairs (issue #1690: truncated replies mid-object should not kill the whole batch); only when even that finds no pairs does it raise, echoing the first 120 chars of the raw text.
Source
Thrown at graphify/llm.py:2935
data: dict | None = None
try:
parsed = json.loads(cleaned)
if isinstance(parsed, dict):
data = parsed
except (json.JSONDecodeError, ValueError):
data = None
if data is None:
# Salvage: pull the complete "<cid>": "<name>" pairs directly. A model
# can truncate its reply mid-object (a stingy token budget or a preamble
# eating the completion), which used to hard-fail the whole batch with
# e.g. `Expecting value: line 1 column 6` on a `{"0":` fragment (#1690).
# Recovering the pairs that DID arrive labels those communities instead
# of dropping the entire batch to placeholders.
pairs = re.findall(r'"?(-?\d+)"?\s*:\s*"([^"\\]*(?:\\.[^"\\]*)*)"', cleaned)
if pairs:
data = {k: v for k, v in pairs}
else:
raise ValueError(f"label response is not parseable JSON: {text[:120]!r}")
out: dict[int, str] = {}
for cid in labeled_cids:
name = data.get(str(cid))
if name is None:
name = data.get(cid)
if isinstance(name, str) and name.strip():
out[cid] = name.strip()
return out
def _label_batch_with_retry(
batch_cids: list[int],
batch_lines: list[str],
*,
backend: str,
model: str | None,
depth: int = 0,
max_depth: int = 3,View on GitHub (pinned to 7fe58b0b0f)
Solutions
- Retry the batch - truncation-based failures are often transient; _label_batch_with_retry exists for this.
- Increase the LLM max-token budget for labeling so the JSON object fits.
- If the echoed text is prose/refusal, tighten the labeling prompt or switch model/backend.
- If the echoed text looks like HTML, fix base_url - you are not talking to the model you think.
Example fix
# before labels = label_batch(cids) # ValueError: label response is not parseable JSON # after - retry via the library's retry wrapper and a bigger budget labels = _label_batch_with_retry(cids, max_tokens=2048) # fallback: accept placeholders for unlabeled communities
Defensive patterns
Strategy: retry
Try / catch
try:
labels = label_batch(cids)
except ValueError as exc:
if "not parseable JSON" in str(exc):
labels = {cid: f"community-{cid}" for cid in cids} # placeholder fallback
log.warning("LLM labels unparseable; using placeholders: %s", exc)
else:
raise Prevention
- Budget max_tokens generously for batch label responses (size the batch times expected name length).
- Inspect the echoed 120-char prefix - it distinguishes truncation from refusal from HTML.
- Keep batches small so one bad reply costs little and the salvage path (partial pairs) has something to save.
When it happens
Trigger: Parsing a label response where json.loads fails AND the pair-regex finds no complete '<cid>': '<name>' structures at all (llm.py:2928-2935) - the reply is pure prose, a fully truncated fragment like '{"0":', or HTML/error text from a gateway.
Common situations: Reasoning/thinking models answering with prose instead of JSON; tiny max_tokens budgets truncating before the first pair; a misrouted base_url returning an HTML error page; prompts mutated by content filters so the model refuses instead of labeling.
Related errors
- claude -p produced unparseable JSON envelope: {exc}; first 5
- claude -p returned a JSON array with no result object; first
- tree-sitter is not installed. Run: pip install 'tree-sitter>
- tree-sitter {getattr(_ts, '__version__', 'unknown')} is too
- could not read Google Workspace shortcut {path}: {exc}
AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14).
Data as JSON: /api/errors/2c90cb34bae28433.
Report an issue: GitHub.