affaan-m/ECC · error · ValueError
empty response
Error message
empty response
What it means
extract_json in the distillation script parses model output into JSON. It raises ValueError('empty response') immediately when the model returned an empty or whitespace-only string, before attempting fence or brace extraction.
Solutions
- Retry the model call; if the provider is intermittently returning empty completions, add a retry with backoff before parsing
- Check the completion's finish_reason / stop reason and token limits (max_tokens) that may have suppressed output
- Log the raw response (length, finish reason) to distinguish filtering, truncation, and auth/quota issues
- Guard the call site: only call extract_json after verifying the response text is non-empty
Example fix
// before
text = client.complete(prompt)
result = extract_json(text)
// after
text = client.complete(prompt)
if not text or not text.strip():
raise RuntimeError(f'model returned empty completion (finish_reason={text.finish_reason})')
result = extract_json(text) Defensive patterns
Strategy: retry
Validate before calling
if not completion or not completion.text.strip():
raise RuntimeError('model returned empty completion; skipping parse') Type guard
def has_text(completion):
return bool(completion and completion.text and completion.text.strip()) Try / catch
for attempt in range(3):
text = client.complete(prompt)
if has_text(text):
break
time.sleep(2 ** attempt)
else:
raise RuntimeError('empty completion after 3 attempts')
result = extract_json(text) Prevention
- Set a sane max_tokens and check finish_reason on every completion
- Log response length and provider stop reasons for every LLM call
- Add a non-empty check before any JSON parsing of model output
- Retry with backoff on empty completions before failing the pipeline
When it happens
Trigger: The LLM call returned an empty completion (empty string or only whitespace/newlines), which is passed to extract_json from describe().
Common situations: Provider returning empty completions due to content filters, max_tokens=0 or exhausted quota, network truncation, or a misconfigured prompt yielding no output; retrying against an unreachable endpoint that returns empty bodies.
Understand the failure class
Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.
Related errors
- analyze() needs at least one frame
- at least one explicit seed is required
- At least one guided harness must be selected
- at least one non-empty
- at least one placement is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/d000758cf33f221b.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-distillation/scripts/distill.py:88
"'}'. Do not wrap it in a code fence. Do not add commentary. Every key "
"listed must be present; use a short string (or list of strings) for each."
)
# ---------------------------------------------------------------------------
# JSON extraction / repair
# ---------------------------------------------------------------------------
def extract_json(text: str) -> dict:
"""Pull a JSON object out of a model reply.
Models wrap JSON in code fences and preambles even when told not to, so a
bare ``json.loads`` fails on output that is otherwise perfectly good.
Fenced content is tried first, then the outermost balanced ``{...}``.
"""
if not text or not text.strip():
raise ValueError("empty response")
candidates: list[str] = []
for m in re.finditer(r"```(?:json)?\s*(.+?)```", text, re.DOTALL | re.IGNORECASE):
candidates.append(m.group(1))
candidates.append(text)
for chunk in candidates:
chunk = chunk.strip()
try:
obj = json.loads(chunk)
if isinstance(obj, dict):
return obj
except json.JSONDecodeError:
pass
span = _balanced_object(chunk)
if span:
try:
obj = json.loads(span)View on GitHub (pinned to 8321021c54)