{"record":{"id":"73fff8ba3640085d","repo":"JuliusBrussee/caveman","slug":"awscreds-s-request-failed-w","errorCode":null,"errorMessage":"awscreds: %s request failed: %w","messagePattern":"awscreds: (.+?) request failed: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/awscreds/awscreds.go","lineNumber":605,"sourceCode":"\t}\n\treturn credentialsFromJSON(credBody, \"imds\")\n}\n\nfunc (p *Provider) imdsGet(ctx context.Context, endpoint, token, what string) ([]byte, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"awscreds: build %s request: %w\", what, err)\n\t}\n\treq.Header.Set(\"X-aws-ec2-metadata-token\", token)\n\treturn p.doJSON(p.link, req, what)\n}\n\n// doJSON performs one attempt and returns the bounded body. A non-2xx response\n// is reported by status only: a metadata body holds credential material.\nfunc (p *Provider) doJSON(client *http.Client, req *http.Request, what string) ([]byte, error) {\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"awscreds: %s request failed: %w\", what, err)\n\t}\n\tdefer resp.Body.Close()\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, maxBody))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"awscreds: read %s response: %w\", what, err)\n\t}\n\tif resp.StatusCode < 200 || resp.StatusCode > 299 {\n\t\treturn nil, fmt.Errorf(\"awscreds: %s: http %d\", what, resp.StatusCode)\n\t}\n\treturn body, nil\n}\n\nfunc credentialsFromJSON(body []byte, source string) (*result, error) {\n\tvar parsed credentialJSON\n\tif err := json.Unmarshal(body, &parsed); err != nil {\n\t\treturn nil, fmt.Errorf(\"awscreds: %s returned an unparseable response\", source)\n\t}\n\tif parsed.Code != \"\" && !strings.EqualFold(parsed.Code, \"Success\") {","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/awscreds/awscreds.go#L587-L623","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nreq, _ := http.NewRequestWithContext(ctx, http.MethodPut, base+\"/latest/api/token\", nil)\n_ = client.Do(req) // hangs 30s on laptop\n// after\nif onEC2() { // gate IMDS use\n    req, _ := http.NewRequestWithContext(ctx, http.MethodPut, base+\"/latest/api/token\", nil)\n    resp, err := client.Do(req)\n}","handlingStrategy":"fallback","validationCode":"reachable, err := isLinkLocalReachable(\"169.254.169.254\") // quick TCP dial\nif err != nil || !reachable {\n    // skip IMDS provider, fall through to env/profile credentials\n}","typeGuard":null,"tryCatchPattern":"creds, err := chain.Credentials(ctx)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) || strings.Contains(err.Error(), \"request failed\") {\n        // fall back to static credentials or fail fast with a clear message\n    }\n}","preventionTips":["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"],"tags":["network","aws","imds","http-client","timeout"],"backgroundTag":"http-request-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}