risingwavelabs/risingwave · error

Vault app role login failed: {} - {}

Error message

Vault app role login failed: {} - {}

What it means

The AppRole login request to Vault (POST /v1/auth/approle/login) returned a non-success HTTP status, so no token could be obtained. When this happens with a previously cached token, that cached token is invalidated in GLOBAL_VAULT_TOKEN_CACHE to force a clean login next time.

Source

Thrown at src/common/secret/src/vault_client.rs:323

                let login_request = VaultAppRoleLoginRequest {
                    role_id: auth_role_id.clone(),
                    secret_id: auth_secret_id.clone(),
                };

                let response = self
                    .client
                    .post(login_url.as_str())
                    .json(&login_request)
                    .send()
                    .await
                    .context("Failed to send app role login request")?;

                if !response.status().is_success() {
                    // If authentication fails and we have a cached token, invalidate it
                    if !force_refresh {
                        GLOBAL_VAULT_TOKEN_CACHE.invalidate(&cache_key).await;
                    }
                    return Err(anyhow::anyhow!(
                        "Vault app role login failed: {} - {}",
                        response.status(),
                        response.text().await.unwrap_or_default()
                    ));
                }

                let auth_response: VaultAuthResponse = response
                    .json()
                    .await
                    .context("Failed to parse Vault auth response")?;

                let token = auth_response.auth.client_token;
                let lease_duration = auth_response.auth.lease_duration;

                // Cache the token with per-entry expiration based on lease duration (90% of lease duration)
                let expires_at = Instant::now() + Duration::from_secs((lease_duration * 9) / 10);
                let cached_token = CachedToken {
                    token: token.clone(),

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check the status/body in the message: 400 usually means invalid role_id or secret_id
  2. Regenerate the secret_id ('vault write auth/approle/role/<role>/secret-id') and update the secret definition
  3. Verify the AppRole auth method is enabled and the role exists ('vault read auth/approle/role/<role>')
  4. Confirm network reachability and that the login endpoint URL/mount is correct
Defensive patterns

Strategy: retry

Validate before calling

// Pre-validate AppRole login outside the data path
let resp = reqwest::Client::new()
    .post(format!("{vault_addr}/v1/auth/approle/login"))
    .json(&serde_json::json!({"role_id": role_id, "secret_id": secret_id}))
    .send().await?;
if !resp.status().is_success() { return Err("invalid role_id/secret_id".into()); }

Try / catch

match result {
    Err(e) if e.to_string().contains("app role login failed") => {
        rotate_secret_id_and_retry().await // credentials are likely expired/revoked
    }
    other => other,
}

Prevention

When it happens

Trigger: get_token_internal sends role_id/secret_id to the AppRole login endpoint and receives e.g. 400 (invalid credentials), 403, or 500; triggered on first use or after a forced token refresh from get_secret.

Common situations: Revoked or expired secret_id; wrong role_id; AppRole auth method not enabled on the mount; Vault policy/ACL changes; clock-skew or replayed secret_id with limited uses.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/11cfeed7101fc750. Report an issue: GitHub.