ZhuLinsen/daily_stock_analysis · error · ValueError
empty_response
Error message
empty_response
What it means
ValueError('empty_response') raised by _extract_analysis_json_object when the LLM response text, after strip(), is empty. This parser expects exactly one JSON object (optionally in a single code fence) describing the AnalysisResult, and an empty body cannot contain one. Unlike the empty-completion case in the generation loop, this error propagates out of the extraction step rather than being retried per-model.
Source
Thrown at src/analyzer.py:4376
prefix = "### 上一次输出如下,请在该输出基础上补齐缺失字段,并重新输出完整 JSON。不要省略已有字段:"
return "\n\n".join([
base_prompt,
prefix,
previous_output,
complement,
])
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)View on GitHub (pinned to 5159bd72e8)
Solutions
- Check the upstream completion: if content is empty, do not invoke extraction — branch to retry/re-fallback at the generation layer.
- Purge or overwrite cached empty analysis responses so they are never re-extracted.
- Fix mocks/tests to return a realistic JSON body.
Example fix
# before
text = cached_response.text # ''
json_str, data = analyzer._extract_analysis_json_object(text) # ValueError: empty_response
# after
if not (cached_response.text or '').strip():
cached_response = regenerate()
json_str, data = analyzer._extract_analysis_json_object(cached_response.text) Defensive patterns
Strategy: validation
Validate before calling
def has_extractable_text(text: str) -> bool:
return bool((text or "").strip()) Try / catch
try:
json_str, data = analyzer._extract_analysis_json_object(text)
except ValueError as e:
if str(e) == "empty_response":
text = regenerate_response() # retry generation, not extraction
json_str, data = analyzer._extract_analysis_json_object(text)
else:
raise Prevention
- Never feed cached/mock/blank texts into the extractor without a strip() check.
- Purge cached empty analysis bodies.
- Fix tests and mocks to return realistic JSON payloads.
When it happens
Trigger: Calling _extract_analysis_json_object('') or with whitespace-only / None-coerced text ('' after response_text or '' check). Typically the downstream half of a completion that returned empty content: generation's empty check was bypassed or the text was passed through from another source (mock, cached entry, plugin).
Common situations: Caching layer storing an empty analysis body and replaying it; tests or mocks returning '' as the assistant message; a prior pipeline stage 'sanitizing' the response into emptiness; refusal responses reduced to blank text.
Related errors
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/aabd3c946fb2d893.
Report an issue: GitHub.