JuliusBrussee/caveman · error
awscreds: request failed
Error message
awscreds: %s request failed: %w
What it means
doJSON wraps the error returned by the HTTP client's Do call for a metadata/credentials request (container or IMDS, labeled by what). This is a transport-level failure — connection refused, timeout, DNS, TLS — not an HTTP status problem.
Solutions
- Confirm you are on an EC2/ECS/EKS instance (curl the metadata IP) before relying on this provider.
- Read the wrapped cause: fix timeouts with larger context deadlines, fix connection-refused by checking the service is running at the endpoint.
- Allow egress to 169.254.169.254 / 169.254.170.2 in network policy/security groups.
- Increase the IMDSv2 hop limit if running from containers (--http-hops).
- Provide credentials through another chain link (env vars, profile, token file) when off AWS infrastructure.
Example fix
// before
req, _ := http.NewRequestWithContext(ctx, http.MethodPut, base+"/latest/api/token", nil)
_ = client.Do(req) // hangs 30s on laptop
// after
if onEC2() { // gate IMDS use
req, _ := http.NewRequestWithContext(ctx, http.MethodPut, base+"/latest/api/token", nil)
resp, err := client.Do(req)
} Defensive patterns
Strategy: fallback
Validate before calling
reachable, err := isLinkLocalReachable("169.254.169.254") // quick TCP dial
if err != nil || !reachable {
// skip IMDS provider, fall through to env/profile credentials
} Try / catch
creds, err := chain.Credentials(ctx)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) || strings.Contains(err.Error(), "request failed") {
// fall back to static credentials or fail fast with a clear message
}
} Prevention
- Gate IMDS usage on running inside EC2/ECS/EKS (IMDSv2 availability check)
- Configure credential_provider preference order with static fallbacks in CI
- Open network-policy holes for 169.254.169.254 and 169.254.170.2 in containers
- Set AWS_EC2_METADATA_DISABLED=true on non-AWS hosts to skip IMDS fast
When it happens
Trigger: client.Do fails for any request issued by fromContainer, fromIMDS, or imdsGet: metadata service unreachable, link-local address absent (not on EC2/ECS), network policy blocking 169.254.x.x, TLS handshake failure, or request timeout.
Common situations: Code that expects IMDS running locally on a laptop/CI runner; security group or iptables rules blocking the metadata link-local address; container network namespace lacking the route; IMDS hop limit (IMDSv2) exhausted in containers; DNS failure for a custom endpoint hostname.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- awscreds: build imds token request
- awscreds: build request
- awscreds: read response
- AbortError
- awscreds: AWS_EC2_METADATA_SERVICE_ENDPOINT is not a valid…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/73fff8ba3640085d.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/awscreds/awscreds.go:605
}
return credentialsFromJSON(credBody, "imds")
}
func (p *Provider) imdsGet(ctx context.Context, endpoint, token, what string) ([]byte, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return nil, fmt.Errorf("awscreds: build %s request: %w", what, err)
}
req.Header.Set("X-aws-ec2-metadata-token", token)
return p.doJSON(p.link, req, what)
}
// doJSON performs one attempt and returns the bounded body. A non-2xx response
// is reported by status only: a metadata body holds credential material.
func (p *Provider) doJSON(client *http.Client, req *http.Request, what string) ([]byte, error) {
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("awscreds: %s request failed: %w", what, err)
}
defer resp.Body.Close()
body, err := io.ReadAll(io.LimitReader(resp.Body, maxBody))
if err != nil {
return nil, fmt.Errorf("awscreds: read %s response: %w", what, err)
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return nil, fmt.Errorf("awscreds: %s: http %d", what, resp.StatusCode)
}
return body, nil
}
func credentialsFromJSON(body []byte, source string) (*result, error) {
var parsed credentialJSON
if err := json.Unmarshal(body, &parsed); err != nil {
return nil, fmt.Errorf("awscreds: %s returned an unparseable response", source)
}
if parsed.Code != "" && !strings.EqualFold(parsed.Code, "Success") {View on GitHub (pinned to 3ee70a1026)