{"record":{"id":"187b96df52c9d0f2","repo":"NousResearch/hermes-agent","slug":"failed-to-initialize-openai-client-e","errorCode":null,"errorMessage":"Failed to initialize OpenAI client: {e}","messagePattern":"Failed to initialize OpenAI client: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"critical","filePath":"agent/agent_init.py","lineNumber":1446,"sourceCode":"            if not agent.quiet_mode:\n                print(f\"🤖 AI Agent initialized with model: {agent.model}\")\n                if base_url:\n                    print(f\"🔗 Using custom base URL: {base_url}\")\n                # ``api_key`` may be a callable Entra ID bearer\n                # provider (Azure Foundry). The OpenAI SDK mints a\n                # fresh JWT per request internally — the banner\n                # never invokes or inspects the callable.\n                from agent.azure_identity_adapter import is_token_provider\n\n                key_used = client_kwargs.get(\"api_key\", \"none\")\n                if is_token_provider(key_used):\n                    print(\"🔑 Using credentials: Microsoft Entra ID\")\n                elif isinstance(key_used, str) and key_used and key_used != \"dummy-key\" and len(key_used) > 12:\n                    print(f\"🔑 Using API key: {key_used[:8]}...{key_used[-4:]}\")\n                else:\n                    print(\"⚠️  Warning: API key appears invalid or missing\")\n        except Exception as e:\n            raise RuntimeError(f\"Failed to initialize OpenAI client: {e}\")\n\n    # Keep a stable identity for the pool entry that supplied this runtime.\n    # OAuth refreshes can replace the runtime token before a failed request is\n    # recovered, so the mutable API-key value alone cannot reliably attribute\n    # the failure to its source entry.\n    from agent.agent_runtime_helpers import sync_credential_pool_entry_id\n    sync_credential_pool_entry_id(agent)\n    \n    # Provider fallback chain — ordered list of backup providers tried\n    # when the primary is exhausted (rate-limit, overload, connection\n    # failure).  Supports both legacy single-dict ``fallback_model`` and\n    # new list ``fallback_providers`` format.\n    if isinstance(fallback_model, list):\n        agent._fallback_chain = [\n            f for f in fallback_model\n            if isinstance(f, dict) and f.get(\"provider\") and f.get(\"model\")\n        ]\n    elif isinstance(fallback_model, dict) and fallback_model.get(\"provider\") and fallback_model.get(\"model\"):","sourceCodeStart":1428,"sourceCodeEnd":1464,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/agent_init.py#L1428-L1464","documentation":"A generic wrapper around ANY exception thrown while constructing the OpenAI-compatible client during agent init — the try block spans key inspection, banner printing, and client construction. The real cause is carried in {e}; this RuntimeError only adds the 'during init' context.","triggerScenarios":"Any constructor failure: malformed model.base_url rejected by httpx, wrong api_key type (dict/None where a string or token-provider callable is expected), broken proxy configuration, azure token-provider errors, or an openai SDK version whose surface changed.","commonSituations":"Custom endpoint URL with a bad port/scheme in config.yaml; OPENAI_BASE_URL typo; openai package upgraded/downgraded out of the pinned range; a model-provider plugin returning an unexpected key type.","solutions":["Read the {e} portion of the message first — it names the actual failure; fix that underlying cause","Validate model.base_url in config.yaml is a well-formed http(s) URL with a valid port","Verify the API key resolves to a string or a token-provider callable, not dict/None","Reinstall the pinned dependency set (uv sync) if the openai SDK surface drifted"],"exampleFix":"# config.yaml — before\nmodel:\n  base_url: \"https://api.example.com:v1\"\n\n# after\nmodel:\n  base_url: \"https://api.example.com/v1\"","handlingStrategy":"try-catch","validationCode":"from urllib.parse import urlparse\n\ndef client_config_sane(base_url: str, api_key) -> str | None:\n    if base_url:\n        try:\n            parsed = urlparse(base_url)\n            if parsed.scheme in {\"http\", \"https\"}:\n                _ = parsed.port  # raises on malformed port\n        except ValueError:\n            return f\"bad base_url: {base_url!r}\"\n    if api_key is not None and not (isinstance(api_key, str) or callable(api_key)):\n        return f\"api_key must be str or callable, got {type(api_key).__name__}\"\n    return None\n\nerr = client_config_sane(base_url, api_key)\nif err:\n    fail_fast(err)","typeGuard":null,"tryCatchPattern":"try:\n    agent = AIAgent(...)\nexcept RuntimeError as e:\n    if str(e).startswith(\"Failed to initialize OpenAI client:\"):\n        underlying = str(e).split(\":\", 1)[1].strip()\n        log_and_report(underlying)  # the {e} suffix is the real cause\n        raise","preventionTips":["Validate base_url shape and api_key type before constructing the agent","Pin the openai dependency range so SDK surface changes cannot break init","Never hand-edit config.yaml URLs without paste-checking them into a URL parser first"],"tags":["initialization","openai","httpx","config"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}