HKUDS/DeepTutor · error · LLMConfigError
OpenAI API key is not configured. Set it in Settings > Catal
Error message
OpenAI API key is not configured. Set it in Settings > Catalog, or select a local provider such as Ollama.
What it means
The SDK executor path (sdk_complete/sdk_stream) validates credentials before handing off to the OpenAI python SDK: provider openai + official endpoint (empty base_url or exactly https://api.openai.com/v1) + placeholder key raises LLMConfigError. It mirrors the config-layer check but runs where the SDK client is constructed, catching direct calls that bypass get_llm_config.
Source
Thrown at deeptutor/services/llm/executors.py:35
from .config import get_token_limit_kwargs
from .exceptions import LLMConfigError
from .utils import extract_response_content
logger = logging.getLogger(__name__)
def _validate_openai_sdk_credentials(
*, provider_name: str | None, api_key: str | None, base_url: str | None
) -> None:
"""Keep placeholder keys from reaching the official OpenAI API."""
provider = (provider_name or "").lower()
endpoint = (base_url or "").rstrip("/")
official_openai = not endpoint or endpoint == "https://api.openai.com/v1"
placeholder = api_key in {None, "", "no-key", "sk-no-key-required"}
if provider == "openai" and official_openai and placeholder:
raise LLMConfigError(
"OpenAI API key is not configured. Set it in Settings > Catalog, "
"or select a local provider such as Ollama."
)
def _is_unsupported_response_format_error(exc: BaseException) -> bool:
"""Detect whether a BadRequestError stems from an unsupported ``response_format``.
Examples seen in the wild:
- LM Studio + Gemma: ``"'response_format.type' must be 'json_schema' or 'text'"``
- DashScope + various models: ``"'response_format.type' specified ... not valid: 'json_object' is not supported by this model"``
"""
text = str(exc).lower()
if "response_format" not in text and "response format" not in text:
return False
return (
"json_object" in text
or "json_schema" in textView on GitHub (pinned to 3e82f13042)
Solutions
- Supply a real OpenAI key when hitting the official endpoint.
- For local servers, pass their actual base_url (e.g. http://localhost:11434/v1) so official_openai is False and placeholder keys are allowed.
- Gate calls: if provider is openai and endpoint is official, require a real key upfront.
- Sync profile resolution so api_key reaches sdk_complete.
Example fix
// before await sdk_complete(prompt=p, model=m, api_key="sk-no-key-required", base_url=None, provider_name="openai") # after await sdk_complete(prompt=p, model=m, api_key=os.environ["OPENAI_API_KEY"], base_url=None, provider_name="openai") # or for local servers: await sdk_complete(prompt=p, model=m, api_key="no-key", base_url="http://localhost:11434/v1", provider_name="openai")
Defensive patterns
Strategy: validation
Validate before calling
PLACEHOLDERS = {None, "", "no-key", "sk-no-key-required"}
official = not (base_url or "").rstrip("/") or (base_url or "").rstrip("/") == "https://api.openai.com/v1"
if (provider_name or "").lower() == "openai" and official and api_key in PLACEHOLDERS:
raise RuntimeError("A real OpenAI key is required for the official endpoint")
await sdk_complete(prompt=p, model=m, api_key=api_key, base_url=base_url, provider_name=provider_name) Type guard
def needs_real_openai_key(api_key, base_url, provider_name) -> bool:
endpoint = (base_url or "").rstrip("/")
official = not endpoint or endpoint == "https://api.openai.com/v1"
placeholder = (api_key or "") in {"", "no-key", "sk-no-key-required"} or api_key is None
return (provider_name or "").lower() == "openai" and official and placeholder Try / catch
try:
out = await sdk_complete(prompt=p, model=m, api_key=k, base_url=u, provider_name=prov)
except LLMConfigError as e:
if "OpenAI API key is not configured" in str(e):
raise RuntimeError("Provide OPENAI_API_KEY or point base_url at your local server") from e
raise Prevention
- Never reuse local-server placeholder keys against the official endpoint.
- Propagate resolved profile credentials into every SDK call site.
- Centralize the official-endpoint + placeholder-key check in one helper.
When it happens
Trigger: Calling sdk_complete(api_key=None, base_url=None, provider_name='openai'); passing the literal placeholders 'no-key'/'sk-no-key-required' (common with local-server defaults) while still targeting the official OpenAI endpoint; profile fields not propagated to the SDK wrapper.
Common situations: Reusing local-server call patterns (which use placeholder keys) against the real OpenAI endpoint; SDK wrapper initialized before settings load; key resolution returning None due to a missing profile key.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- OpenAI API key is not configured. Set it in Settings > Catal
- Anthropic API key is missing from the active LLM profile.
- Cohere API key is missing from the active LLM profile.
- OpenAI API error: {error_text}
- Cloud completion failed: no valid configuration
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/a70296a094154adc.
Report an issue: GitHub.