ZhuLinsen/daily_stock_analysis · error · ValueError
ambiguous_json
Error message
ambiguous_json
What it means
ValueError('ambiguous_json') raised by _extract_analysis_json_object when the response contains MORE THAN ONE fenced ``` code block. The parser's contract is a single JSON object; multiple fences mean the model emitted several candidates (or fenced prose plus JSON) and picking one arbitrarily could silently deserialize the wrong payload, so it refuses instead of guessing.
Source
Thrown at src/analyzer.py:4384
def _apply_placeholder_fill(self, result: AnalysisResult, missing_fields: List[str]) -> None:
"""Delegate to module-level apply_placeholder_fill."""
apply_placeholder_fill(result, missing_fields)
def _extract_analysis_json_object(self, response_text: str) -> Tuple[str, Dict[str, Any]]:
"""Extract the single allowed JSON object from an LLM response."""
text = response_text or ""
stripped = text.strip()
if not stripped:
raise ValueError("empty_response")
fence_pattern = re.compile(
r"```[ \t]*(?P<lang>[A-Za-z0-9_-]*)[ \t]*\n?(?P<body>.*?)```",
flags=re.DOTALL,
)
fenced_matches = list(fence_pattern.finditer(text))
if len(fenced_matches) > 1:
raise ValueError("ambiguous_json")
if len(fenced_matches) == 1:
match = fenced_matches[0]
outside = (text[:match.start()] + text[match.end():]).strip()
if outside:
raise ValueError("ambiguous_json")
fence_lang = (match.group("lang") or "").strip().lower()
if fence_lang not in {"", "json"}:
raise ValueError("ambiguous_json")
json_str = match.group("body").strip()
data = self._load_analysis_json_candidate(json_str)
return json_str, data
if "```" in text:
raise ValueError("ambiguous_json")
try:
data = self._load_analysis_json_candidate(stripped)
except json.JSONDecodeError as exc:
if self._contains_embedded_json_object(text):View on GitHub (pinned to 5159bd72e8)
Solutions
- Tighten the analysis prompt: demand ONLY one fenced ```json block with no other code blocks, and forbid examples in the output.
- If extra fences are deterministic (e.g. always a known-language example first), strip them upstream before calling the extractor — but only with a deterministic rule, not a guess.
- Retry generation with a corrective message when this error occurs, since the same model often complies on the second attempt.
Example fix
# before (prompt) "Think step by step, show any code samples, then give the JSON report in a fence." # model emits 2 fences -> ValueError: ambiguous_json # after (prompt) "Respond with exactly one ```json fenced block containing the report object and nothing else."
Defensive patterns
Strategy: retry
Validate before calling
import re
FENCE = re.compile(r"```[^`]*?```", re.DOTALL)
def single_fence_only(text: str) -> bool:
return len(FENCE.findall(text or "")) <= 1 Try / catch
for attempt in range(2):
try:
return extract(text)
except ValueError as e:
if str(e) == "ambiguous_json" and attempt == 0:
text = regenerate_with("Output exactly one ```json block and nothing else.")
continue
raise Prevention
- Prompt for exactly one ```json fence; forbid other code blocks.
- Avoid few-shot examples that demonstrate multiple fences.
- Do not regex-pick one of several fences — fix the prompt instead.
When it happens
Trigger: _extract_analysis_json_object on text like "```json\n{...}\n```\nSome notes\n```\n{...}\n```" — any response where the fence regex finds 2+ matches. Common when the model explains its answer with example blocks or emits both a summary and the result as separate fences.
Common situations: Prompts that ask for 'reasoning then JSON in a code block' (model fences both); few-shot examples in the prompt teaching multi-fence output; model regressions/switches that add commentary fences around the answer.
Related errors
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/c972a41af0a6d1b2.
Report an issue: GitHub.