NousResearch/hermes-agent · error · RuntimeError

Bitwarden refresh did not return secrets for {missing}. Eit

Error message

Bitwarden refresh did not return secrets for {missing}.  Either add the secrets to your BWS project, switch to credential_source: env via `hermes egress setup --no-bitwarden`, or set `proxy.allow_env_fallback: true` in config.yaml to opt into the legacy host-env fallback.

What it means

With credential_source=bitwarden, the BWS refresh ran but returned nothing for some required secret names. Because the operator explicitly chose Bitwarden for rotation, the code fails closed rather than silently falling back to possibly-stale host-env values (the 'stephenschoettler #1' fix); allow_env_fallback=true is the only documented opt-out.

Source

Thrown at agent/proxy_sources/iron_proxy.py:2188

                # Only inject env names we have a mapping for — extra
                # secrets in the BW project shouldn't leak into the proxy
                # process unless they're going to be used by the swap.
                missing = sorted(needed - set(secrets))
                for n in needed:
                    if n in secrets:
                        env[n] = secrets[n]
                if missing:
                    # stephenschoettler #1: don't silently keep stale
                    # host-env values when BWS mode was explicitly
                    # selected.  An operator on credential_source=bitwarden
                    # picked it specifically to get rotation; falling back
                    # to parent env reintroduces the bug class the mode
                    # is supposed to defeat.  ``allow_env_fallback`` is the
                    # documented, deliberate opt-out — honor it here exactly
                    # as the empty-token branch below does (the error
                    # message tells operators to set it, so it must work).
                    if not (bitwarden_config or {}).get("allow_env_fallback"):
                        raise RuntimeError(
                            f"Bitwarden refresh did not return secrets for "
                            f"{missing}.  Either add the secrets to your BWS "
                            f"project, switch to credential_source: env via "
                            f"`hermes egress setup --no-bitwarden`, or set "
                            f"`proxy.allow_env_fallback: true` in config.yaml "
                            f"to opt into the legacy host-env fallback."
                        )
                    logger.warning(
                        "Bitwarden refresh did not return secrets for %s — "
                        "falling back to host env for those names "
                        "(allow_env_fallback=true).",
                        missing,
                    )
                # bws warnings are non-secret status messages (e.g. "no
                # project found", "rate limited"), but the taint analyzer
                # can't tell that — log the count and let the operator
                # rerun under verbose if they need detail.
                if warnings:

View on GitHub (pinned to c896c09c42)

Solutions

  1. Add the missing secret name(s) (listed in the message) to the BWS project referenced by project_id, then retry
  2. If you intend host-env values to be used, set proxy.allow_env_fallback: true in config.yaml (deliberate legacy opt-in)
  3. Or stop using BWS for this proxy: switch to credential_source: env via `hermes egress setup --no-bitwarden`
  4. Verify names match exactly (case/whitespace) with `hermes secrets bitwarden status`

Example fix

# before: project lacks 'IRON_TOKEN'
# RuntimeError: Bitwarden refresh did not return secrets for ('IRON_TOKEN',)
bws secret list --access-token $BWS_TOKEN --project <id>  # confirm absence
bws secret create IRON_TOKEN <value> --project <id>
hermes egress start

# after: refresh populates env[n] for every required name
Defensive patterns

Strategy: try-catch

Validate before calling

from agent.secret_sources.bitwarden import list_project_secret_names  # conceptual

def bws_project_covers(project_id: str, required: set[str]) -> bool:
    try:
        return required <= set(list_project_secret_names(project_id))
    except Exception:
        return False

# gate proxy start on bws_project_covers(pid, REQUIRED_SECRET_NAMES)

Try / catch

try:
    start_proxy(...)
except RuntimeError as e:
    if 'Bitwarden refresh did not return' in str(e):
        # missing names are listed in the message: add them, or consciously opt out
        add_missing_to_bws(str(e)) or set_allow_env_fallback()
        start_proxy(...)

Prevention

When it happens

Trigger: Starting/refreshing the egress proxy with credential_source=bitwarden where the BWS project lacks one or more of the required secret names (missing set is in {missing}), or the access token can read the project but those items are deleted/renamed.

Common situations: Secret renamed or removed in the Bitwarden web vault after initial setup; secrets created in a different BWS project than project_id points at; token scopes narrowed so some items are filtered out of the response.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/72951fb4bacbfc4c. Report an issue: GitHub.