ducaale/xh · error

message-signature: Failed to parse PEM private key…

Error message

message-signature: Failed to parse PEM private key. Supported algorithms: ed25519, ecdsa-p256-sha256, ecdsa-p384-sha384, rsa-v1_5-sha256, rsa-pss-sha512

What it means

build_signing_key failed to parse the supplied PEM private key with any supported algorithm's parser. After ruling out RSA keys needing explicit algorithm selection, it bails listing the supported algorithms: ed25519, ecdsa-p256-sha256, ecdsa-p384-sha384, rsa-v1_5-sha256, rsa-pss-sha512.

Solutions

  1. Verify the file is an unencrypted PEM private key (check BEGIN PRIVATE KEY header)
  2. Use a supported key type: ed25519, ECDSA P-256/P-384, or RSA (with explicit --unstable-m-sig-alg)
  3. Re-export the key without a passphrase and in PKCS#8 PEM format
  4. If intending HMAC, pass the raw secret without PEM markers

Example fix

# before (public key passed)
http --message-signature key=pubkey.pem ...
# after (private key, supported format)
http --message-signature key=ed25519_private.pem ...
Defensive patterns

Strategy: validation

Validate before calling

// pre-check the PEM before signing
fn pem_looks_valid(key: &str) -> bool {
    key.contains("-----BEGIN") && key.contains("PRIVATE KEY-----") && !key.contains("ENCRYPTED")
}
assert!(pem_looks_valid(&std::fs::read_to_string("key.pem")?));

Type guard

fn is_supported_private_pem(pem: &str) -> bool {
    pem.contains("PRIVATE KEY-----") && !pem.contains("ENCRYPTED") && !pem.contains("PUBLIC KEY")
}

Try / catch

match sign_request(&req, &components, &key) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("Failed to parse PEM private key") => {
        eprintln!("check key format; supported: ed25519, ecdsa-p256-sha256, ecdsa-p384-sha384, rsa-v1_5-sha256, rsa-pss-sha512");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: sign_request called with key material that is neither a parseable ed25519/ECDSA/RSA PEM nor valid HMAC secret, e.g. malformed PEM, encrypted PEM, a public key instead of a private key, or an unsupported key type.

Common situations: Wrong file passed as key (certificate or public key); PEM encrypted with a passphrase; truncated/corrupted PEM; unsupported curve or key format (PKCS#8 variants not handled).

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/1c5e797b614726c8. Report an issue: GitHub.

Appendix: source

Thrown at src/message_signature.rs:275

                    AlgorithmName::Ed25519,
                    AlgorithmName::EcdsaP256Sha256,
                    AlgorithmName::EcdsaP384Sha384,
                ],
            ) {
                let alg = secret.alg();
                return Ok((MessageSigningKey::Secret(secret, key_id.to_string()), alg));
            }
            if parse_pem_secret_key(
                pem,
                &[AlgorithmName::RsaV1_5Sha256, AlgorithmName::RsaPssSha512],
            )
            .is_some()
            {
                bail!(
                    "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,

View on GitHub (pinned to 2404aceecc)