stalwartlabs/stalwart · error

Failed to decode base64

Error message

Failed to decode base64

What it means

`base64_decode` in the console module wraps `base64::general_purpose::STANDARD.decode(input)` in `.expect("Failed to decode base64")`, so any invalid base64 input panics. It is used by `parse_key`/`parse_value` when console input is prefixed with `base64:`, and by PEM/blob/pkey parsing helpers (simple_pem_parse, get_blob_section, parse_public_key, verify_secret_hash). Standard-alphabet decoding with strict padding is enforced; URL-safe characters or missing/incorrect padding cause the panic.

Source

Thrown at crates/common/src/manager/console.rs:247

        Some(result)
    } else {
        println!("Invalid key: {result:?}");
        None
    }
}

fn parse_value(input: &str) -> Vec<u8> {
    if let Some(key) = input.strip_prefix("base64:") {
        base64_decode(key)
    } else {
        parse_binary(input)
    }
}

fn base64_decode(input: &str) -> Vec<u8> {
    general_purpose::STANDARD
        .decode(input)
        .expect("Failed to decode base64")
}

fn parse_binary(input: &str) -> Vec<u8> {
    let mut result = Vec::new();
    let mut chars = input.chars().peekable();

    while let Some(c) = chars.next() {
        if c == '\\' {
            match chars.next() {
                Some('x') => {
                    let hex: String = chars.by_ref().take(2).collect();
                    if hex.len() == 2 {
                        if let Ok(byte) = u8::from_str_radix(&hex, 16) {
                            result.push(byte);
                        } else {
                            result.extend_from_slice(b"\\x");
                            result.extend_from_slice(hex.as_bytes());
                        }

View on GitHub (pinned to e962003857)

Solutions

  1. Validate the base64 string before use: only A-Z a-z 0-9 + / with proper = padding (or re-pad it), e.g. decode it first with `base64 -d` or a quick script.
  2. Re-encode the data in standard (padded) base64: `echo -n "<raw>" | base64` and use that output after the `base64:` prefix.
  3. Convert URL-safe base64 to standard: replace `-` with `+`, `_` with `/`, and append the required `=` padding before decoding.
  4. Strip all whitespace/newlines from the payload before passing it, and use the `\xNN` escaped-hex input format as a fallback when base64 keeps failing.

Example fix

// before
scan base64:cmFjYXNk base64:cmFjYXNkZg   // missing padding -> panic

// after
scan base64:cmFjYXNk base64:cmFjYXNkZg==   // correct standard padding
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_standard_base64(s: &str) -> bool {
    let trimmed: String = s.chars().filter(|c| !c.is_whitespace()).collect();
    base64::engine::general_purpose::STANDARD.decode(&trimmed).is_ok()
}
// call before passing `base64:<payload>` to console commands

Type guard

fn safe_base64_decode(input: &str) -> Option<Vec<u8>> {
    base64::engine::general_purpose::STANDARD.decode(input).ok()
}

Try / catch

// replace .expect with fallible handling
fn base64_decode(input: &str) -> Result<Vec<u8>, base64::DecodeError> {
    base64::engine::general_purpose::STANDARD.decode(input)
}

Prevention

When it happens

Trigger: Typing `scan/get/put/delete` console arguments like `base64:abc!` or `base64:cmV` (invalid character, wrong length, or missing padding); passing a PEM blob, public key, or secret hash string containing URL-safe base64 (`-`/`_`), whitespace inside the payload, or truncated data into the parsing helpers.

Common situations: Pasting base64 from tools that produce URL-safe base64 (JWT segments, some JSON serializers) into the console; copying base64 with line breaks that were stripped incorrectly leaving stray characters; hand-truncating a key and losing `=` padding; base64 of a value copied from a doc with typographic characters.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of stalwartlabs/stalwart@e962003857 (2026-09-06). Data as JSON: /api/errors/a093182d0d986c12. Report an issue: GitHub.