{"record":{"id":"3618b360d13f1538","repo":"NousResearch/hermes-agent","slug":"no-available-openai-codex-credential-in-credential","errorCode":null,"errorMessage":"No available openai-codex credential in credential pool","messagePattern":"No available openai-codex credential in credential pool","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/account_usage.py","lineNumber":506,"sourceCode":"            account_id = str(tokens.get(\"account_id\", \"\") or \"\").strip() or None\n        except AuthError:\n            # Pool-only creds carry no singleton account_id; header is optional.\n            logger.debug(\"codex ▸ /usage account_id read failed (best-effort)\", exc_info=True)\n        return creds[\"api_key\"], str(creds.get(\"base_url\", \"\") or \"\").strip(), account_id\n    except AuthError:\n        logger.debug(\"codex ▸ /usage runtime resolver returned no creds; trying pool\", exc_info=True)\n\n    # Tier 3: direct pool select. Reached only when the resolver itself raises\n    # AuthError (e.g. singleton missing AND its own pool read found nothing at\n    # resolve time, but a pool entry is usable now). Pool credentials have no\n    # account_id concept, so the ChatGPT-Account-Id header is intentionally\n    # omitted here.\n    from agent.credential_pool import load_pool\n\n    pool = load_pool(\"openai-codex\")\n    entry = pool.select()\n    if entry is None:\n        raise RuntimeError(\"No available openai-codex credential in credential pool\")\n    return entry.runtime_api_key, str(entry.runtime_base_url or base_url or \"\").strip(), None\n\n\ndef _fetch_codex_account_usage(\n    base_url: Optional[str] = None,\n    api_key: Optional[str] = None,\n) -> Optional[AccountUsageSnapshot]:\n    token, resolved_base_url, account_id = _resolve_codex_usage_credentials(base_url, api_key)\n    headers = {\n        \"Authorization\": f\"Bearer {token}\",\n        \"Accept\": \"application/json\",\n        \"User-Agent\": \"codex-cli\",\n    }\n    if account_id:\n        headers[\"ChatGPT-Account-Id\"] = account_id\n    with httpx.Client(timeout=15.0) as client:\n        response = client.get(_resolve_codex_usage_url(resolved_base_url), headers=headers)\n        response.raise_for_status()","sourceCodeStart":488,"sourceCodeEnd":524,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/agent/account_usage.py#L488-L524","documentation":"Raised by the tier-3 fallback in _resolve_codex_usage_credentials (agent/account_usage.py:506) when fetching Codex account usage. Tier 1 (the runtime resolver) already raised AuthError, and tier 2's direct pool select via load_pool('openai-codex').select() returned None, so no usable Codex credential exists anywhere in the process. It is a RuntimeError because usage-fetching cannot proceed without any credential to authenticate with.","triggerScenarios":"Any code path that calls _fetch_codex_account_usage() (usage banner, account quota checks) while (a) the openai-codex runtime resolver raises AuthError and (b) load_pool('openai-codex').select() returns None — empty pool file, all entries disabled/exhausted, or a fresh HERMES_HOME with no codex credentials.","commonSituations":"User never authenticated with openai-codex; pool entries all tripped by the rate-limit breaker; profile's HERMES_HOME points at a new directory without the credential pool; pool file corrupted so select() yields nothing.","solutions":["Authenticate openai-codex again (hermes setup / provider login) so load_pool('openai-codex').select() returns an entry","Inspect the credential pool under get_hermes_home() for openai-codex entries and re-enable or refresh disabled/expired ones","If running under a profile, confirm HERMES_HOME points at the profile that actually holds the codex credentials","If usage display is optional at the call site, catch the RuntimeError and skip the usage read"],"exampleFix":"# before\nusage = _fetch_codex_account_usage()  # raises when no codex credential exists\n\n# after\ntry:\n    usage = _fetch_codex_account_usage()\nexcept RuntimeError:\n    usage = None  # no codex credential configured; skip usage display","handlingStrategy":"try-catch","validationCode":"from agent.credential_pool import load_pool\n\ndef has_codex_credential() -> bool:\n    try:\n        return load_pool(\"openai-codex\").select() is not None\n    except Exception:\n        return False\n\n# before fetching usage:\nif not has_codex_credential():\n    skip_usage_display()","typeGuard":null,"tryCatchPattern":"try:\n    usage = _fetch_codex_account_usage(base_url, api_key)\nexcept RuntimeError as e:\n    if \"No available openai-codex credential\" in str(e):\n        usage = None  # no codex creds configured — skip usage UI\n    else:\n        raise","preventionTips":["Authenticate openai-codex before enabling usage displays that depend on it","Treat codex usage as best-effort: wrap fetch calls and degrade to 'unknown' instead of crashing","Under profiles, verify the active HERMES_HOME carries the codex credential pool"],"tags":["credentials","codex","usage","auth"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}