{"record":{"id":"a70296a094154adc","repo":"HKUDS/DeepTutor","slug":"openai-api-key-is-not-configured-set-it-in-settin-a70296","errorCode":null,"errorMessage":"OpenAI API key is not configured. Set it in Settings > Catalog, or select a local provider such as Ollama.","messagePattern":"OpenAI API key is not configured\\. Set it in Settings > Catalog, or select a local provider such as Ollama\\.","errorType":"validation","errorClass":"LLMConfigError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/llm/executors.py","lineNumber":35,"sourceCode":"\nfrom .config import get_token_limit_kwargs\nfrom .exceptions import LLMConfigError\nfrom .utils import extract_response_content\n\nlogger = logging.getLogger(__name__)\n\n\ndef _validate_openai_sdk_credentials(\n    *, provider_name: str | None, api_key: str | None, base_url: str | None\n) -> None:\n    \"\"\"Keep placeholder keys from reaching the official OpenAI API.\"\"\"\n\n    provider = (provider_name or \"\").lower()\n    endpoint = (base_url or \"\").rstrip(\"/\")\n    official_openai = not endpoint or endpoint == \"https://api.openai.com/v1\"\n    placeholder = api_key in {None, \"\", \"no-key\", \"sk-no-key-required\"}\n    if provider == \"openai\" and official_openai and placeholder:\n        raise LLMConfigError(\n            \"OpenAI API key is not configured. Set it in Settings > Catalog, \"\n            \"or select a local provider such as Ollama.\"\n        )\n\n\ndef _is_unsupported_response_format_error(exc: BaseException) -> bool:\n    \"\"\"Detect whether a BadRequestError stems from an unsupported ``response_format``.\n\n    Examples seen in the wild:\n    - LM Studio + Gemma: ``\"'response_format.type' must be 'json_schema' or 'text'\"``\n    - DashScope + various models: ``\"'response_format.type' specified ... not valid: 'json_object' is not supported by this model\"``\n    \"\"\"\n    text = str(exc).lower()\n    if \"response_format\" not in text and \"response format\" not in text:\n        return False\n    return (\n        \"json_object\" in text\n        or \"json_schema\" in text","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/llm/executors.py#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait sdk_complete(prompt=p, model=m, api_key=\"sk-no-key-required\", base_url=None, provider_name=\"openai\")\n\n# after\nawait sdk_complete(prompt=p, model=m, api_key=os.environ[\"OPENAI_API_KEY\"], base_url=None, provider_name=\"openai\")\n# or for local servers:\nawait sdk_complete(prompt=p, model=m, api_key=\"no-key\", base_url=\"http://localhost:11434/v1\", provider_name=\"openai\")","handlingStrategy":"validation","validationCode":"PLACEHOLDERS = {None, \"\", \"no-key\", \"sk-no-key-required\"}\nofficial = not (base_url or \"\").rstrip(\"/\") or (base_url or \"\").rstrip(\"/\") == \"https://api.openai.com/v1\"\nif (provider_name or \"\").lower() == \"openai\" and official and api_key in PLACEHOLDERS:\n    raise RuntimeError(\"A real OpenAI key is required for the official endpoint\")\nawait sdk_complete(prompt=p, model=m, api_key=api_key, base_url=base_url, provider_name=provider_name)","typeGuard":"def needs_real_openai_key(api_key, base_url, provider_name) -> bool:\n    endpoint = (base_url or \"\").rstrip(\"/\")\n    official = not endpoint or endpoint == \"https://api.openai.com/v1\"\n    placeholder = (api_key or \"\") in {\"\", \"no-key\", \"sk-no-key-required\"} or api_key is None\n    return (provider_name or \"\").lower() == \"openai\" and official and placeholder","tryCatchPattern":"try:\n    out = await sdk_complete(prompt=p, model=m, api_key=k, base_url=u, provider_name=prov)\nexcept LLMConfigError as e:\n    if \"OpenAI API key is not configured\" in str(e):\n        raise RuntimeError(\"Provide OPENAI_API_KEY or point base_url at your local server\") from e\n    raise","preventionTips":["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."],"tags":["llm","openai","sdk","authentication","api-key"],"backgroundTag":"missing-api-key","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}