JuliusBrussee/caveman · error

bedrock: could not build signing request

Error message

bedrock: could not build signing request: %w

What it means

Before SigV4 signing, the proxy builds a synthetic http.Request carrying the upstream URL with http.NewRequestWithContext. If that construction fails (invalid method or unparseable upstream URL), the error is wrapped and returned. This indicates the proxy could not even assemble the request it intends to sign — an internal/proxy configuration problem, not an AWS rejection.

Solutions

  1. Inspect the upstream URL built for the Bedrock provider and verify it is a valid absolute http(s) URL (scheme, host, no stray spaces/control chars)
  2. Check that req.Method is a valid HTTP method token (GET/POST/...) and was not corrupted upstream
  3. Log the wrapped inner error (%w) to see whether url.Parse or the method was the culprit and fix the provider/route configuration accordingly

Example fix

// before
upstream := "bedrock-runtime." + region + ".amazonaws com/completions"
// after
upstream := "https://bedrock-runtime." + region + ".amazonaws.com/completions"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(upstreamURL)
if err != nil || u.Scheme == "" || u.Host == "" {
	return fmt.Errorf("invalid upstream URL %q: %w", upstreamURL, err)
}
if !validMethod(req.Method) { return fmt.Errorf("invalid method %q", req.Method) }

Try / catch

if err := sanitizeAndMap(); err != nil {
	var buildErr *url.Error
	if errors.As(err, &buildErr) { log.Printf("bad upstream URL: %v", buildErr) }
}

Prevention

When it happens

Trigger: http.NewRequestWithContext fails inside SanitizeAndMapHeaders, e.g. the resolved upstream URL fails url.Parse (bad scheme/host characters) or req.Method is an invalid HTTP method token.

Common situations: Misconfigured upstream base URL for the Bedrock provider (typos, stray spaces, missing scheme, control characters injected from env vars); a rewrite middleware producing a malformed path/query; custom or lowercase-with-spaces HTTP method set by an earlier handler.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/8616d0cb15cc3295. Report an issue: GitHub.

Appendix: source

Thrown at proxy/providers/bedrock/signing.go:106

	// (SignatureDoesNotMatch). Fall back to a self-resolve only if the caller passed
	// nil (no forward URL available).
	if upstream == nil {
		upstream, err = a.ResolveUpstreamURL(ctx, req, providers.RouteContext{})
		if err != nil {
			return nil, err
		}
	}
	if credential.Scheme == "sigv4" && !matchesInboundSigningIdentity(req, upstream, creds) {
		return nil, ErrSigV4Configuration
	}

	// Build a synthetic request carrying the upstream host/path/query and the
	// to-be-signed headers, sign it, then merge the signed headers into out. This
	// keeps the signing surface (host, path, query, x-amz-*) identical to what the
	// proxy actually sends upstream.
	toSign, err := http.NewRequestWithContext(ctx, req.Method, upstream.String(), nil)
	if err != nil {
		return nil, fmt.Errorf("bedrock: could not build signing request: %w", err)
	}
	toSign.Header = out.Clone()

	signingService := runtimeService
	if mantle {
		signingService = mantleService
	}
	payloadHash, err := requestPayloadHash(ctx, req)
	if err != nil {
		return nil, err
	}
	signer := awssig.Signer{Region: signingRegion(req, upstream), Service: signingService}
	if err := signer.Sign(toSign, creds, payloadHash, time.Now()); err != nil {
		// The error from Sign never contains the secret (see awssig docs); still,
		// return a generic mapping error rather than the raw text.
		return nil, fmt.Errorf("bedrock: request signing failed")
	}

View on GitHub (pinned to 3ee70a1026)