juspay/hyperswitch · error · GcpKmsError

Failed to base64 decode input data

Error message

Failed to base64 decode input data

What it means

Thrown by GcpKmsClient::decrypt when the input data cannot be base64 decoded. The decrypt API expects ciphertext in base64 (matching the output of encrypt, which returns base64-encoded ciphertext). If the bytes passed are not valid base64 for the configured engine (standard padded base64), decoding fails and this error is returned. It occurs before any network call to GCP KMS is made.

Source

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

                logger::error!(gcp_kms_error=?error, "Failed to GCP KMS encrypt data");
                metrics::GCP_KMS_ENCRYPTION_FAILURES.add(1, &[]);
            })
            .change_context(GcpKmsError::EncryptionFailed)?;

        let output = consts::BASE64_ENGINE.encode(response.ciphertext);

        let time_taken = start.elapsed();
        metrics::GCP_KMS_ENCRYPT_TIME.record(time_taken.as_secs_f64(), &[]);

        Ok(output)
    }
}

/// Errors that could occur during GCP KMS operations.
#[derive(Debug, thiserror::Error)]
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,
}

View on GitHub (pinned to 806ec7dcc0)

Solutions

  1. Verify the input is valid standard base64 before calling decrypt (decode it with base64::engine::general_purpose::STANDARD in a test)
  2. If the ciphertext came from another system, check whether it uses base64url (- and _ instead of + and /) and translate or use the appropriate engine
  3. Ensure the ciphertext was produced by GcpKmsClient::encrypt, which returns standard base64 with padding
  4. Inspect stored/transferred ciphertext for truncation, embedded newlines, or URL-encoding artifacts

Example fix

// before: passing raw binary or non-padded base64
let plaintext = client.decrypt(raw_ciphertext_bytes).await?;

// after: ensure input is standard padded base64, as produced by encrypt()
use base64::Engine;
let normalized = ciphertext_str.trim();
let validated = base64::engine::general_purpose::STANDARD
    .decode(normalized)
    .map_err(|e| format!("not valid base64: {e}"))?;
let plaintext = client.decode_pre_validated(validated).await?; // or just pass `normalized`
Defensive patterns

Strategy: validation

Validate before calling

use base64::Engine;

fn is_valid_standard_b64(input: &str) -> bool {
    base64::engine::general_purpose::STANDARD
        .decode(input.trim())
        .is_ok()
}

// before calling decrypt:
if !is_valid_standard_b64(&ciphertext) {
    return Err("ciphertext is not valid base64");
}
let plaintext = client.decrypt(ciphertext.trim()).await?;

Try / catch

match client.decrypt(data).await {
    Ok(s) => s,
    Err(e) if matches!(e.current_context(), GcpKmsError::Base64DecodingFailed) => {
        // reject the stored ciphertext / alert on data corruption; do not retry
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling GcpKmsClient::decrypt with a string/bytes that is not valid base64 (e.g. raw binary ciphertext, corrupted/modified base64, wrong padding or charset, or ciphertext produced by a different encoding scheme such as base64url without translation). Raised at the consts::BASE64_ENGINE.decode(data) call in crates/external_services/src/gcp_kms/core.rs:86-88.

Common situations: Passing raw binary ciphertext that was never base64 encoded; round-tripping data through a system that strips or re-encodes padding; using base64url-encoded tokens from JWTs or external APIs; double-decoding or truncation of the ciphertext in transit or storage; copy-pasting ciphertext with whitespace/newlines embedded.

Related errors


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