VictoriaMetrics/VictoriaMetrics · error

cannot create request for IMDSv2 session token at url %q: %w

Error message

cannot create request for IMDSv2 session token at url %q: %w

What it means

This error is wrapped when http.NewRequest fails to construct the PUT request that fetches an IMDSv2 session token from the EC2 instance metadata endpoint (http://169.254.169.254/latest/api/token). getMetadataByPath builds this request before contacting the metadata service; if the request object itself cannot be created, the library wraps the underlying error. In practice this almost always indicates an invalid URL or method passed to http.NewRequest, which for the hard-coded session token URL is extremely rare.

Source

Thrown at lib/awsapi/config.go:468

// MetadataSecurityCredentials represents credentials obtained from http://169.254.169.254/latest/meta-data/iam/security-credentials/*
//
// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html
type MetadataSecurityCredentials struct {
	AccessKeyID     string    `json:"AccessKeyId"`
	SecretAccessKey string    `json:"SecretAccessKey"`
	Token           string    `json:"Token"`
	Expiration      time.Time `json:"Expiration"`
}

// getMetadataByPath returns instance metadata by url path
func getMetadataByPath(client *http.Client, apiPath string) ([]byte, error) {
	// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html

	// Obtain session token
	sessionTokenURL := "http://169.254.169.254/latest/api/token"
	req, err := http.NewRequest(http.MethodPut, sessionTokenURL, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot create request for IMDSv2 session token at url %q: %w", sessionTokenURL, err)
	}
	req.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "60")
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("cannot obtain IMDSv2 session token from %q: %w", sessionTokenURL, err)
	}
	token, err := readResponseBody(resp, sessionTokenURL)
	if err != nil {
		return nil, fmt.Errorf("cannot read IMDSv2 session token from %q: %w", sessionTokenURL, err)
	}

	// Use session token in the request.
	apiURL := "http://169.254.169.254/latest/" + apiPath
	req, err = http.NewRequest(http.MethodGet, apiURL, nil)
	if err != nil {
		return nil, fmt.Errorf("cannot create request to %q: %w", apiURL, err)
	}
	req.Header.Set("X-aws-ec2-metadata-token", string(token))

View on GitHub (pinned to 5079fb58f1)

Solutions

  1. Verify the session token URL is the stock value (http://169.254.169.254/latest/api/token) and was not modified or templated incorrectly
  2. Unwrap the %w error (errors.Unwrap / errors.As on *url.Error) to see the root cause from net/url
  3. Check for custom forks/patches of lib/awsapi that altered the URL construction
  4. If seen in tests, fix the test harness that substitutes the metadata endpoint URL

Example fix

// before
sessionTokenURL := os.Getenv("IMDS_URL") // may be empty/malformed
req, err := http.NewRequest(http.MethodPut, sessionTokenURL, nil)
// after
sessionTokenURL := "http://169.254.169.254/latest/api/token"
if u, perr := url.Parse(sessionTokenURL); perr != nil || u.Host == "" {
    return nil, fmt.Errorf("invalid IMDS URL %q", sessionTokenURL)
}
req, err := http.NewRequest(http.MethodPut, sessionTokenURL, nil)
Defensive patterns

Strategy: try-catch

Validate before calling

// Run before calling config resolution that may hit IMDS
func canBuildTokenRequest() error {
    _, err := http.NewRequest(http.MethodPut, "http://169.254.169.254/latest/api/token", nil)
    return err
}

Try / catch

cfg, err := awsapi.NewConfig()
if err != nil {
    if strings.Contains(err.Error(), "cannot create request for IMDSv2 session token") {
        var urlErr *url.Error
        if errors.As(err, &urlErr) { log.Printf("IMDS request build failed: %v", urlErr) }
    }
    return fmt.Errorf("aws config: %w", err)
}

Prevention

When it happens

Trigger: http.NewRequest(http.MethodPut, "http://169.254.169.254/latest/api/token", nil) returns an error — e.g. an unparsable URL or unsupported method. With the hard-coded URL/method this only happens via exotic failures (e.g. url.Parse misbehavior from corrupted builds or custom RoundTripper/test harnesses injecting a different URL).

Common situations: Custom test stubs or forked code that parameterize the metadata URL with a malformed value; go-http internals failing on an invalid net/url; virtually never seen in production with the stock URL.

Related errors


AI-assisted analysis of VictoriaMetrics/VictoriaMetrics@5079fb58f1 (2026-09-03). Data as JSON: /api/errors/0cf49dd9fb5d35b0. Report an issue: GitHub.