{"record":{"id":"edeb58b0df49c73d","repo":"JuliusBrussee/caveman","slug":"awscreds-build-imds-token-request-w","errorCode":null,"errorMessage":"awscreds: build imds token request: %w","messagePattern":"awscreds: build imds token request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/awscreds/awscreds.go","lineNumber":554,"sourceCode":"\nfunc (p *Provider) fromIMDS(ctx context.Context) (*result, error) {\n\tif strings.EqualFold(p.env(\"AWS_EC2_METADATA_DISABLED\"), \"true\") {\n\t\treturn nil, nil\n\t}\n\tbase := p.env(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\")\n\tif base == \"\" {\n\t\tbase = defaultIMDSBase\n\t}\n\tif err := checkIMDSEndpoint(base); err != nil {\n\t\treturn nil, err\n\t}\n\tbase = strings.TrimSuffix(base, \"/\")\n\n\t// IMDSv2 only: a v1 fallback would leave the proxy vulnerable to the SSRF\n\t// class the session token exists to close.\n\ttokenReq, err := http.NewRequestWithContext(ctx, http.MethodPut, base+\"/latest/api/token\", nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"awscreds: build imds token request: %w\", err)\n\t}\n\t// One minute: this token authorizes the two metadata GETs immediately below\n\t// and is then dropped. The six-hour maximum only widens the window in which a\n\t// leaked token is still usable.\n\ttokenReq.Header.Set(\"X-aws-ec2-metadata-token-ttl-seconds\", \"60\")\n\ttokenBody, err := p.doJSON(p.link, tokenReq, \"imds token\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttoken := strings.TrimSpace(string(tokenBody))\n\tif token == \"\" {\n\t\treturn nil, errors.New(\"awscreds: imds returned an empty session token\")\n\t}\n\n\troleBody, err := p.imdsGet(ctx, base+\"/latest/meta-data/iam/security-credentials/\", token, \"imds role\")\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/awscreds/awscreds.go#L536-L572","documentation":"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.","triggerScenarios":"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.","commonSituations":"Endpoint env var with embedded whitespace or control characters; context deadline exceeded before the call; programmatically constructed base URL missing the scheme.","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)."],"exampleFix":"// before\nos.Setenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\", \"http://169.254.169.254\\n\")\n// after\nos.Setenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\", strings.TrimSpace(endpoint))","handlingStrategy":"try-catch","validationCode":"if ep := os.Getenv(\"AWS_EC2_METADATA_SERVICE_ENDPOINT\"); ep != \"\" {\n    if _, err := url.Parse(strings.TrimSpace(ep)); err != nil {\n        return fmt.Errorf(\"bad IMDS endpoint: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"var urlErr *url.Error\nif errors.As(err, &urlErr) {\n    if errors.Is(urlErr.Err, context.Canceled) || errors.Is(urlErr.Err, context.DeadlineExceeded) {\n        // extend timeout and retry\n    }\n}","preventionTips":["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"],"tags":["aws","imds","http-client","url-format"],"backgroundTag":"invalid-url-format","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"}