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_service

View on GitHub (pinned to 3e82f13042)

Solutions

  1. Increase max_tokens for the probe (reasoning models can burn 64 tokens with no visible output)
  2. Verify provider config — API key, base_url, model name — in Settings and re-run diagnostics
  3. 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

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


AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27). Data as JSON: /api/errors/cf6aade659841a87. Report an issue: GitHub.