ducaale/xh · error

message-signature: Failed to create HMAC key

Error message

message-signature: Failed to create HMAC key: {:?}

What it means

While building an HMAC-SHA256 shared signing key, the base64-encoded key material is passed to `SharedKey::from_base64`, which validates the encoding. If that call fails (e.g. the material is not valid base64 after re-encoding, or fails key constraints), the error is wrapped with this message via `anyhow!` and propagated up through `build_signing_key`.

Solutions

  1. Verify the key material is valid base64 of the correct length for HMAC-SHA256; re-encode with `base64 -w0 < keyfile`.
  2. Check for stray whitespace, quotes, or newlines in the value passed via `--unstable-m-sig-key` or the env var.
  3. Confirm the key is raw key bytes (not PEM/hex); convert appropriately before passing it.

Example fix

// before
xh --unstable-m-sig-id=k1 --unstable-m-sig-key="$(cat key.pem)" POST https://api.example.com
// after
xh --unstable-m-sig-id=k1 --unstable-m-sig-key="$(base64 -w0 key.bin)" POST https://api.example.com
Defensive patterns

Strategy: validation

Validate before calling

# validate base64 key material before use:
echo "$KEY" | base64 -d >/dev/null 2>&1 || { echo 'key is not valid base64'; exit 1; }

Try / catch

// Rust caller:
match build_signing_key_with_algorithm(...) {
    Err(e) if e.to_string().contains("Failed to create HMAC key") => {
        eprintln!("check key encoding: must be valid base64 raw key bytes");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Passing `--unstable-m-sig-key` material that `SharedKey::from_base64` rejects for the HmacSha256 algorithm — e.g. malformed base64 content or an invalid key length for the algorithm.

Common situations: Pasting a key with whitespace/newlines; supplying a PEM or hex key where raw/base64 material is expected; truncating a key when copying it from a secret manager.

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 ducaale/xh@2404aceecc (2026-09-13). Data as JSON: /api/errors/b6de6fc580d63286. Report an issue: GitHub.

Appendix: source

Thrown at src/message_signature.rs:290

                    "message-signature: RSA private keys require an explicit algorithm. Use --unstable-m-sig-alg=rsa-v1_5-sha256 or --unstable-m-sig-alg=rsa-pss-sha512"
                );
            }
            bail!(
                "message-signature: Failed to parse PEM private key. Supported algorithms: ed25519, ecdsa-p256-sha256, ecdsa-p384-sha384, rsa-v1_5-sha256, rsa-pss-sha512"
            );
        }
    }

    build_hmac_signing_key(key_material, key_id)
}

fn build_hmac_signing_key(
    key_material: &[u8],
    key_id: &str,
) -> Result<(MessageSigningKey, AlgorithmName)> {
    let encoded = STANDARD.encode(key_material);
    let shared_key = SharedKey::from_base64(&AlgorithmName::HmacSha256, &encoded)
        .map_err(|e| anyhow!("message-signature: Failed to create HMAC key: {:?}", e))?;
    Ok((
        MessageSigningKey::Shared(shared_key, key_id.to_string()),
        AlgorithmName::HmacSha256,
    ))
}

fn build_signing_key_with_algorithm(
    key_material: &[u8],
    key_id: &str,
    algorithm: &AlgorithmName,
) -> Result<(MessageSigningKey, AlgorithmName)> {
    if algorithm == &AlgorithmName::HmacSha256 {
        return build_hmac_signing_key(key_material, key_id);
    }

    let secret = if let Ok(pem) = std::str::from_utf8(key_material) {
        if pem.contains("-----BEGIN") {
            SecretKey::from_pem(algorithm, pem).with_context(|| {

View on GitHub (pinned to 2404aceecc)