juspay/hyperswitch · critical · GcpKmsError

Failed to create GCP KMS client

Error message

Failed to create GCP KMS client

What it means

Thrown by GcpKmsClient::new when either ClientConfig::default().with_auth() fails to obtain ambient GCP credentials, or Client::new fails to construct the KMS client (channel/gRPC setup). This is a startup/config-time error: no credentials, unreachable metadata server, or invalid ADC configuration. The underlying error is converted via change_context.

Source

Thrown at crates/external_services/src/gcp_kms/core.rs:168

pub enum GcpKmsError {
    /// An error occurred when base64 decoding the input data.
    #[error("Failed to base64 decode input data")]
    Base64DecodingFailed,

    /// An error occurred when GCP KMS decrypting the input data.
    #[error("Failed to GCP KMS decrypt input data")]
    DecryptionFailed,

    /// An error occurred when GCP KMS encrypting the input data.
    #[error("Failed to GCP KMS encrypt input data")]
    EncryptionFailed,

    /// An error occurred UTF-8 decoding the GCP KMS decrypted output.
    #[error("Failed UTF-8 decode of GCP KMS decrypted output")]
    Utf8DecodingFailed,

    /// An error occurred when creating the GCP KMS client.
    #[error("Failed to create GCP KMS client")]
    ClientCreationFailed,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn validate_fails_when_project_id_is_empty() {
        let config = GcpKmsConfig {
            project_id: String::new(),
            location_id: "global".to_string(),
            key_ring_id: "key-ring".to_string(),
            key_id: "key".to_string(),
        };
        assert!(config.validate().is_err());
    }

View on GitHub (pinned to 806ec7dcc0)

Solutions

  1. Run gcloud auth application-default login locally, or set GOOGLE_APPLICATION_CREDENTIALS to the service account JSON path
  2. Verify credentials resolve: gcloud auth application-default print-access-token
  3. On GKE, check Workload Identity binding for the pod's service account; on GCE, confirm the metadata server is reachable (169.254.169.254)
  4. Inspect the error_chain/attached source via error_stack Display to see the exact auth failure (expired token, file not found, channel error)
  5. Ensure network egress to cloudkms.googleapis.com:443 is allowed

Example fix

# before: container starts with no ADC
RUN echo "no creds baked"
ENV GOOGLE_APPLICATION_CREDENTIALS=

# after: mount SA credentials and point ADC at them
docker run -v $PWD/sa.json:/secrets/sa.json \
  -e GOOGLE_APPLICATION_CREDENTIALS=/secrets/sa.json \
  my-service
Defensive patterns

Strategy: try-catch

Validate before calling

// Fail fast at boot before any business logic:
if let Err(msg) = gcp_kms_config.validate() {
    return Err(format!("invalid GCP KMS config: {msg}"));
}
// Optionally probe ADC availability first (cheap local check):
#[cfg(feature = "gcp")] {
    if std::env::var("GOOGLE_APPLICATION_CREDENTIALS").is_err()
        && !gcloud_adc_exists()
        && !running_on_gcp_metadata()
    {
        return Err("no Application Default Credentials found for GCP KMS");
    }
}
let kms = GcpKmsClient::new(&gcp_kms_config).await?;

Try / catch

match GcpKmsClient::new(&config).await {
    Ok(client) => client,
    Err(e) if matches!(e.current_context(), GcpKmsError::ClientCreationFailed) => {
        // startup-fatal: print the full error_stack chain (auth vs channel)
        // and abort with a clear config error rather than retrying blindly
        let mut msg = String::from("GCP KMS client creation failed:");
        for frame in e.chain() {
            msg.push_str(&format!("\n  caused by: {frame}"));
        }
        anyhow::bail!(msg);
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling GcpKmsClient::new(&config) where with_auth() cannot resolve Application Default Credentials (no GOOGLE_APPLICATION_CREDENTIALS, no gcloud ADC, not on GCE/GKE with metadata server), or Client::new fails (cannot establish gRPC channel to cloudkms.googleapis.com). See crates/external_services/src/gcp_kms/core.rs:66-73.

Common situations: Local development without running gcloud auth application-default login; missing GOOGLE_APPLICATION_CREDENTIALS env var in containers/CI; service account JSON expired or malformed; workload identity not configured on GKE; egress proxy/firewall blocking metadata server or cloudkms.googleapis.com; readonly filesystem preventing ADC cache.

Related errors


AI-assisted analysis of juspay/hyperswitch@806ec7dcc0 (2026-08-28). Data as JSON: /api/errors/4b3886150972dd93. Report an issue: GitHub.