hermes - ✅(Solved) Fix Custom providers sharing same base_url use wrong API credentials [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#14141Fetched 2026-04-23 07:46:36
View on GitHub
Comments
0
Participants
1
Timeline
7
Reactions
0
Author
Participants
Timeline (top)
labeled ×5cross-referenced ×2

Root Cause

In hermes_cli/runtime_provider.py, the function _resolve_named_custom_runtime calls _try_resolve_from_custom_pool(base_url, "custom", ...) to get credentials from the shared credential pool. The pool is keyed by base_url, so when multiple custom providers share the same base_url, the pool lookup returns whichever provider was registered first in the configuration, ignoring the actual requested provider.

Fix Action

Workaround

Currently, the only workaround is to ensure each custom provider uses a unique base_url, which is not always possible when using a unified API gateway.

PR fix notes

PR #14142: Fix: Custom providers sharing same base_url use wrong API credentials

Description (problem / solution / changelog)

Summary

Fixes #14141

When multiple custom_providers share the same base_url (e.g., all pointing to a unified API gateway), the credential pool resolution in _resolve_named_custom_runtime returns credentials from the first matching provider instead of the requested provider.

Changes

  • Modified _resolve_named_custom_runtime() in hermes_cli/runtime_provider.py to prioritize the provider's own api_key field before falling back to the shared credential pool
  • This ensures each provider uses its configured credentials even when sharing a base_url with other providers

Root Cause

The credential pool is keyed by base_url. When multiple custom providers share the same base_url, the pool lookup (get_custom_provider_pool_key()) returns whichever provider was registered first in the configuration, ignoring the actual requested provider.

Testing

  • Verified that switching between multiple custom providers with the same base_url now uses the correct API key for each
  • Confirmed that requests are properly authenticated and routed to the correct channels

Backward Compatibility

This change is backward compatible. Providers that don't have their own api_key will still fall back to the credential pool and environment variables as before.

Changed files

  • hermes_cli/runtime_provider.py (modified, +27/-18)

PR #14144: fix(runtime): keep named custom provider keys isolated

Description (problem / solution / changelog)

Summary

  • avoid reusing a shared custom-endpoint credential pool when its pool key maps to a different named provider
  • keep the existing pool path for the named provider that actually owns the pool key
  • add a regression test for two named custom providers sharing the same base URL

Testing

  • pytest -o addopts="" tests/hermes_cli/test_runtime_provider_resolution.py -k "uses_own_api_key_before_shared_pool or propagates_model_pool_path"
  • pytest -o addopts="" tests/hermes_cli/test_runtime_provider_resolution.py

Fixes #14141

Changed files

  • hermes_cli/runtime_provider.py (modified, +28/-10)
  • tests/hermes_cli/test_runtime_provider_resolution.py (modified, +53/-0)
RAW_BUFFERClick to expand / collapse

Bug Description

When multiple custom_providers are configured with the same base_url (e.g., all pointing to a unified API gateway), the credential pool resolution in _resolve_named_custom_runtime matches by base_url and returns the credentials of the first matching provider, not the requested provider.

Root Cause

In hermes_cli/runtime_provider.py, the function _resolve_named_custom_runtime calls _try_resolve_from_custom_pool(base_url, "custom", ...) to get credentials from the shared credential pool. The pool is keyed by base_url, so when multiple custom providers share the same base_url, the pool lookup returns whichever provider was registered first in the configuration, ignoring the actual requested provider.

Impact

  • Switching between custom providers that share the same base_url uses incorrect API keys
  • Requests may fail with authentication errors (401) or be routed to wrong channels/groups
  • Users cannot reliably use multiple providers through a single API gateway

Reproduction Steps

  1. Configure multiple custom_providers with the same base_url but different api_key values
  2. Switch model to a provider that is NOT the first one in the configuration list
  3. Observe that the wrong API key is used (can be verified via logs or authentication errors)

Suggested Fix

Modify _resolve_named_custom_runtime to prioritize the provider's own api_key field before falling back to the shared credential pool. This ensures each provider uses its configured credentials even when sharing a base_url with other providers.

Related Code

  • hermes_cli/runtime_provider.py - _resolve_named_custom_runtime() function
  • hermes_cli/runtime_provider.py - _try_resolve_from_custom_pool() function
  • hermes_cli/runtime_provider.py - get_custom_provider_pool_key() function

Workaround

Currently, the only workaround is to ensure each custom provider uses a unique base_url, which is not always possible when using a unified API gateway.

extent analysis

TL;DR

Modify the _resolve_named_custom_runtime function to prioritize the provider's own api_key field before falling back to the shared credential pool to fix the credential resolution issue.

Guidance

  • Review the _resolve_named_custom_runtime function in hermes_cli/runtime_provider.py to understand how it currently resolves credentials and how it can be modified to prioritize the provider's own api_key.
  • Consider modifying the get_custom_provider_pool_key function to include a unique identifier for each provider, in addition to the base_url, to ensure correct credential lookup.
  • Test the modification with multiple custom providers sharing the same base_url to verify that each uses its configured credentials correctly.
  • Evaluate the feasibility of using unique base_url values for each custom provider as a temporary workaround, if the modification cannot be implemented immediately.

Example

# Example of how _resolve_named_custom_runtime could be modified
def _resolve_named_custom_runtime(provider_name):
    # First, try to get credentials from the provider's own api_key field
    provider = get_custom_provider(provider_name)
    if provider and provider['api_key']:
        return provider['api_key']
    
    # If not found, fall back to the shared credential pool
    return _try_resolve_from_custom_pool(provider['base_url'], "custom")

Notes

The suggested fix requires modifying the existing codebase, specifically the _resolve_named_custom_runtime function. This change should be thoroughly tested to ensure it does not introduce any regressions. Additionally, the workaround of using unique base_url values for each custom provider may not be feasible in all scenarios, especially when using a unified API gateway.

Recommendation

Apply the workaround of using unique base_url values for each custom provider if possible, until the modification to the _resolve_named_custom_runtime function can be implemented and tested. This ensures that each provider uses its correct credentials, albeit with the limitation of requiring unique base_url values.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING