{"record":{"id":"8c29d4c9232f3b6e","repo":"affaan-m/ECC","slug":"authenticationerror-msg-provider-providertype-openai-from-e","errorCode":null,"errorMessage":"AuthenticationError(msg, provider=ProviderType.OPENAI) from e","messagePattern":"AuthenticationError\\(msg, provider=ProviderType\\.OPENAI\\) from e","errorType":"exception","errorClass":"AuthenticationError","httpStatus":null,"severity":"error","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/8321021c54d670126ce3b2969d5deb880b4b0c2a/src/llm/providers/openai.py#L99-L132","documentation":"The OpenAI provider wraps exceptions whose message contains '401' or 'authentication' into AuthenticationError with provider=OPENAI. This means the API key was missing, malformed, revoked, or belonging to the wrong org/project.","triggerScenarios":"Calling generate() with an unset OPENAI_API_KEY, a revoked/rotated key, a key from a different org without project access, or an 'Incorrect API key provided' error from the SDK.","commonSituations":"Missing env var in CI or deployment; key pasted with whitespace/quotes; org revoked the key; using an old sk-... key after migration to project-scoped keys.","solutions":["Verify OPENAI_API_KEY is set and non-empty in the environment","Regenerate the key in the OpenAI dashboard and update the secret store","Strip whitespace/quotes: export OPENAI_API_KEY=$(printenv OPENAI_API_KEY | xargs)","Confirm the key belongs to the correct org/project with API access"],"exampleFix":"// before\nclient = OpenAI(api_key=\"\")\n// after\napi_key = os.environ[\"OPENAI_API_KEY\"]\nassert api_key, \"OPENAI_API_KEY not set\"\nclient = OpenAI(api_key=api_key)","handlingStrategy":"validation","validationCode":"import os\nkey = os.environ.get(\"OPENAI_API_KEY\")\nassert key and key.startswith(\"sk-\") and len(key) > 20, \"OPENAI_API_KEY missing or malformed\"","typeGuard":null,"tryCatchPattern":"try:\n    resp = provider.generate(inp)\nexcept AuthenticationError as e:\n    logger.error(\"OpenAI auth failed — check OPENAI_API_KEY: %s\", type(e).__name__)\n    raise","preventionTips":["Validate required env vars at startup","Store keys in a secret manager, never in code","Rotate keys on a schedule and update deployments","Test key validity with a cheap models.list call"],"tags":["openai","authentication","api-key"],"backgroundTag":"missing-api-key","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}