HKUDS/DeepTutor · error · RuntimeError
The model returned an empty response.
Error message
The model returned an empty response.
What it means
The doctor's _probe_provider makes a tiny LLM call (max_tokens=64, max_retries=0, no image fallback) and raises RuntimeError when the response text is empty after stripping. It distinguishes 'provider reachable' from 'provider returned nothing', which often indicates auth/quota/model issues the API did not surface as an error status.
Source
Thrown at deeptutor/services/doctor.py:342
from deeptutor.services.llm import complete
response = await complete(
model=str(config.model),
prompt="Reply with OK.",
system_prompt="Reply with only OK.",
binding=str(config.binding),
api_key=str(config.api_key or ""),
base_url=str(config.effective_url or config.base_url or ""),
api_version=config.api_version,
temperature=0,
extra_headers=config.extra_headers,
reasoning_effort=config.reasoning_effort,
max_retries=0,
allow_image_fallback=False,
max_tokens=64,
)
if not (response or "").strip():
raise RuntimeError("The model returned an empty response.")
async def run_diagnostics(
*,
online: bool = False,
resolve_llm: Callable[[], Any] | None = None,
data_root: Path | None = None,
load_rag_config: Callable[[], dict[str, Any]] | None = None,
rag_preflight: Callable[[str], dict[str, Any]] | None = None,
online_probe: Callable[[Any], Awaitable[None]] | None = None,
) -> DoctorReport:
"""Run setup diagnostics without network access unless ``online`` is set."""
if resolve_llm is None:
from deeptutor.services.config import resolve_llm_runtime_config
resolve_llm = resolve_llm_runtime_config
if data_root is None:
from deeptutor.services.path_service import get_path_serviceView on GitHub (pinned to 3e82f13042)
Solutions
- Increase max_tokens for the probe (reasoning models can burn 64 tokens with no visible output)
- Verify provider config — API key, base_url, model name — in Settings and re-run diagnostics
- Bypass the gateway: test the same key with curl to confirm non-empty completions
Example fix
# before
resp = await client.chat.completions.create(..., max_tokens=64)
# after
resp = await client.chat.completions.create(..., max_tokens=512)
if not (resp.text or "").strip():
raise RuntimeError("empty response — check key/quota/base_url") Defensive patterns
Strategy: try-catch
Try / catch
try:
await run_diagnostics(online=True)
except RuntimeError as e:
if "empty response" in str(e):
report("provider reachable but returned empty output — check key/quota/model")
raise Prevention
- Probe with enough max_tokens for reasoning models (>=512)
- Verify base_url/key with curl before diagnosing app-level issues
- Treat empty-but-200 responses as config smells, not successes
When it happens
Trigger: run_diagnostics(online=True) probing a provider whose endpoint returns 200 with empty content, or a reasoning model that spends all 64 tokens invisibly leaving no visible text.
Common situations: Misconfigured base_url pointing at a gateway that swallows content; quota exhausted so the backend returns empty bodies; reasoning models consuming the tiny token budget before emitting text.
Related errors
- Cloud completion failed: no valid configuration
- TTS provider returned empty audio.
- LLM did not return any code.
- LLM returned no deep-dive suggestions.
- LLM did not return any flashcards.
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/cf6aade659841a87.
Report an issue: GitHub.