headroomlabs-ai/headroom · error · SigV4Error::Sign

bedrock_sigv4_failed

bedrock_sigv4_failed

Error message

sigv4 signing failed: {0}

What it means

The aws-sigv4 signing crate rejected the Bedrock request during signing — URL parse failure or malformed header are the canonical causes listed on the variant. Signing happens per-request in sigv4.rs before the outbound call, so this aborts the request before it ever reaches Bedrock.

Source

Thrown at crates/headroom-proxy/src/bedrock/sigv4.rs:94

}

/// Headers that the signer will write into the outbound request.
/// The handler must add every entry to the upstream-bound HeaderMap
/// before sending — Bedrock validates each header against the
/// canonical request.
#[derive(Debug, Clone)]
pub struct SignedHeaders {
    pub entries: Vec<(String, String)>,
    /// Lowercase hex SHA-256 of the body. Surfaced for tests + logs.
    pub signature: String,
}

/// Errors surfaced by the signing path.
#[derive(Debug, Error)]
pub enum SigV4Error {
    /// `aws-sigv4` rejected the request (URL parse, malformed header,
    /// etc).
    #[error("sigv4 signing failed: {0}")]
    Sign(String),
    /// The signing-params builder rejected the inputs (e.g. missing
    /// region — should never happen because we validate at startup).
    #[error("sigv4 builder error: {0}")]
    Builder(String),
}

/// Sign a Bedrock request and return the headers the handler must add
/// to the outbound request.
///
/// # Cache safety
///
/// The body bytes passed in MUST be the bytes the proxy is about to
/// send upstream. If the compressor mutated the body, those mutated
/// bytes are what get signed — Bedrock will accept because the
/// signature covers the wire payload, not the original.
///
/// # Errors

View on GitHub (pinned to 322425c43b)

Solutions

  1. Inspect the {0} inner string — it embeds the aws-sigv4 error and names the offending component (URL vs header).
  2. Validate/normalize the configured Bedrock endpoint URL at startup (scheme + host well-formed) so bad config fails fast, not per-request.
  3. Sanitize or drop hop-by-hop and malformed client headers before signing rather than passing them through.
  4. Pin or align the aws-sigv4 version with what this crate was tested against if an upgrade introduced stricter checks.
Defensive patterns

Strategy: validation

Validate before calling

// Validate the endpoint once at startup
fn valid_upstream(url: &str) -> bool {
    url::Url::parse(url).map(|u| matches!(u.scheme(), "http" | "https")).unwrap_or(false)
}

Try / catch

match sign_request(&req, &creds, region).await {
    Err(SigV4Error::Sign(e)) => {
        tracing::error!(error = %e, "signing rejected request");
        // fail the request — signing failures are not transient
        return Err(ProxyError::InvalidHeader(e));
    }
    r => r,
}

Prevention

When it happens

Trigger: Sign() invoked with a URL the signer cannot parse (unusual scheme, invalid characters); a request header value containing bytes/characters aws-sigv4 refuses; an HTTP method or signing configuration the crate's HttpSignatureProblem wrapping rejects.

Common situations: A custom --bedrock-base-url / endpoint override with a malformed URL; injected headers (from client passthrough) containing newlines or non-ASCII that poison signing; version bump of aws-sigv4 tightening validation on previously-tolerated input.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/9c0730683ba55b48. Report an issue: GitHub.