{"record":{"id":"b73675af86d10ca2","repo":"affaan-m/ECC","slug":"msg-b73675","errorCode":null,"errorMessage":"{msg}","messagePattern":"\\{msg\\}","errorType":"exception","errorClass":"AuthenticationError","httpStatus":401,"severity":"critical","filePath":"src/llm/providers/openai.py","lineNumber":117,"sourceCode":"            usage = None\n            if response.usage:\n                usage = {\n                    \"prompt_tokens\": response.usage.prompt_tokens,\n                    \"completion_tokens\": response.usage.completion_tokens,\n                    \"total_tokens\": response.usage.total_tokens,\n                }\n\n            return LLMOutput(\n                content=choice.message.content or \"\",\n                tool_calls=tool_calls,\n                model=response.model,\n                usage=usage,\n                stop_reason=choice.finish_reason,\n            )\n        except Exception as e:\n            msg = str(e)\n            if \"401\" in msg or \"authentication\" in msg.lower():\n                raise AuthenticationError(msg, provider=ProviderType.OPENAI) from e\n            if \"429\" in msg or \"rate_limit\" in msg.lower():\n                raise RateLimitError(msg, provider=ProviderType.OPENAI) from e\n            if \"context\" in msg.lower() and \"length\" in msg.lower():\n                raise ContextLengthError(msg, provider=ProviderType.OPENAI) from e\n            raise\n\n    def list_models(self) -> list[ModelInfo]:\n        return self._models.copy()\n\n    def validate_config(self) -> bool:\n        return bool(self.client.api_key)\n\n    def get_default_model(self) -> str:\n        return \"gpt-4o-mini\"\n","sourceCodeStart":99,"sourceCodeEnd":132,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/src/llm/providers/openai.py#L99-L132","documentation":"OpenAIProvider.generate() raises AuthenticationError when the caught exception message contains '401' or 'authentication'. The OpenAI client is constructed with _enforce_credentials=False, so it builds happily even with an empty/missing key and fails later at request time. For the official SDK this maps to an invalid, expired, or revoked key, or a request to a model/endpoint the key's project cannot access.","triggerScenarios":"OPENAI_API_KEY unset or empty (client still constructs due to _enforce_credentials=False); key revoked or rotated; key lacks permission for the requested model; base_url points at a proxy that requires its own auth.","commonSituations":"Missing .env / env var; CI secret not injected; key rotated but old value cached; using an org key for a model in a different project; Azure/proxy base_url with a credential meant for another backend.","solutions":["Verify OPENAI_API_KEY is set and call provider.validate_config() (returns True when the key is non-empty) before generate().","Regenerate the key in the OpenAI dashboard and rotate the stored secret.","Confirm the key's project can access the requested model.","If using base_url for a proxy, supply the proxy's required auth, not the OpenAI key."],"exampleFix":"// before\nprovider = OpenAIProvider()\noutput = provider.generate(llm_input)\n\n// after\nimport os\nfrom llm.core.interface import AuthenticationError\n\nif not os.environ.get(\"OPENAI_API_KEY\"):\n    raise SystemExit(\"Set OPENAI_API_KEY\")\nprovider = OpenAIProvider()\nassert provider.validate_config(), \"OpenAI key missing\"\ntry:\n    output = provider.generate(llm_input)\nexcept AuthenticationError:\n    rotate_key()\n    raise","handlingStrategy":"validation","validationCode":"import os\nfrom llm.providers.openai import OpenAIProvider\n\ndef openai_ready() -> bool:\n    return bool(os.environ.get(\"OPENAI_API_KEY\")) and OpenAIProvider().validate_config()","typeGuard":"from llm.core.interface import AuthenticationError\n\ndef is_auth_error(exc: BaseException) -> bool:\n    return isinstance(exc, AuthenticationError)","tryCatchPattern":"from llm.core.interface import AuthenticationError\n\ntry:\n    output = provider.generate(llm_input)\nexcept AuthenticationError as e:\n    logger.error(\"OpenAI auth failed — rotate key: %s\", e)\n    raise","preventionTips":["Call provider.validate_config() at startup before any generate() call.","Inject keys via a secret manager, not hard-coded env files.","Rotate keys on a schedule and fail fast on 401.","If using a proxy base_url, document which credential it expects."],"tags":["openai","authentication","llm-provider","api-key","credentials"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}