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

  1. Confirm you are on an EC2/ECS/EKS instance (curl the metadata IP) before relying on this provider.
  2. Read the wrapped cause: fix timeouts with larger context deadlines, fix connection-refused by checking the service is running at the endpoint.
  3. Allow egress to 169.254.169.254 / 169.254.170.2 in network policy/security groups.
  4. Increase the IMDSv2 hop limit if running from containers (--http-hops).
  5. 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

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


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)