JuliusBrussee/caveman · error
awscreds: build imds token request
Error message
awscreds: build imds token request: %w
What it means
fromIMDS wraps an error from http.NewRequestWithContext while building the IMDSv2 PUT request to /latest/api/token. The library throws this because the resolved IMDS base URL could not be turned into a request, so no session token can be fetched.
Solutions
- Validate AWS_EC2_METADATA_SERVICE_ENDPOINT is a clean absolute http(s) URL.
- Ensure the context passed to the provider has not already been canceled; check the wrapped cause for 'context canceled' vs 'net/url' parse errors.
- Unset the endpoint env var to use the default IMDS address.
- Trim whitespace/newlines when setting the env var programmatically (strings.TrimSpace).
Example fix
// before
os.Setenv("AWS_EC2_METADATA_SERVICE_ENDPOINT", "http://169.254.169.254\n")
// after
os.Setenv("AWS_EC2_METADATA_SERVICE_ENDPOINT", strings.TrimSpace(endpoint)) Defensive patterns
Strategy: try-catch
Validate before calling
if ep := os.Getenv("AWS_EC2_METADATA_SERVICE_ENDPOINT"); ep != "" {
if _, err := url.Parse(strings.TrimSpace(ep)); err != nil {
return fmt.Errorf("bad IMDS endpoint: %w", err)
}
} Try / catch
var urlErr *url.Error
if errors.As(err, &urlErr) {
if errors.Is(urlErr.Err, context.Canceled) || errors.Is(urlErr.Err, context.DeadlineExceeded) {
// extend timeout and retry
}
} Prevention
- Give IMDS calls a context with a few seconds of headroom
- Sanitize endpoint env vars (TrimSpace) at startup
- Check errors.As(*url.Error) to distinguish parse vs context causes
When it happens
Trigger: The IMDS base URL (from AWS_EC2_METADATA_SERVICE_ENDPOINT or the default) produces an invalid request URL after trimming/concatenation, or the passed context is already canceled/expired before the token PUT.
Common situations: Endpoint env var with embedded whitespace or control characters; context deadline exceeded before the call; programmatically constructed base URL missing the scheme.
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
- awscreds: build request
- awscreds: request failed
- awscreds: AWS_EC2_METADATA_SERVICE_ENDPOINT is not a valid…
- awscreds: build container credentials request
- awscreds: no AWS credentials found (env, web identity…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/edeb58b0df49c73d.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/awscreds/awscreds.go:554
func (p *Provider) fromIMDS(ctx context.Context) (*result, error) {
if strings.EqualFold(p.env("AWS_EC2_METADATA_DISABLED"), "true") {
return nil, nil
}
base := p.env("AWS_EC2_METADATA_SERVICE_ENDPOINT")
if base == "" {
base = defaultIMDSBase
}
if err := checkIMDSEndpoint(base); err != nil {
return nil, err
}
base = strings.TrimSuffix(base, "/")
// IMDSv2 only: a v1 fallback would leave the proxy vulnerable to the SSRF
// class the session token exists to close.
tokenReq, err := http.NewRequestWithContext(ctx, http.MethodPut, base+"/latest/api/token", nil)
if err != nil {
return nil, fmt.Errorf("awscreds: build imds token request: %w", err)
}
// One minute: this token authorizes the two metadata GETs immediately below
// and is then dropped. The six-hour maximum only widens the window in which a
// leaked token is still usable.
tokenReq.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "60")
tokenBody, err := p.doJSON(p.link, tokenReq, "imds token")
if err != nil {
return nil, err
}
token := strings.TrimSpace(string(tokenBody))
if token == "" {
return nil, errors.New("awscreds: imds returned an empty session token")
}
roleBody, err := p.imdsGet(ctx, base+"/latest/meta-data/iam/security-credentials/", token, "imds role")
if err != nil {
return nil, err
}View on GitHub (pinned to 3ee70a1026)