kubernetes/kops · error

failed to get droplet region: %s

Error message

failed to get droplet region: %s

What it means

New() builds the DigitalOcean nodeidentifier and first needs the Droplet's region, read from the DigitalOcean metadata service (169.254.169.254). If getMetadataRegion fails (metadata service unreachable, error response, or unparseable body), New aborts with "failed to get droplet region". Without the region the DO API client cannot be scoped correctly.

Source

Thrown at pkg/nodeidentity/do/identify.go:67

	cache        expirationcache.Store
	cacheEnabled bool
}

// TokenSource implements oauth2.TokenSource.
type TokenSource struct {
	AccessToken string
}

// Token returns an oauth2.Token for the configured access token.
func (t *TokenSource) Token() (*oauth2.Token, error) {
	return &oauth2.Token{AccessToken: t.AccessToken}, nil
}

// New creates and returns a nodeidentity.Identifier for nodes running on DigitalOcean.
func New(cacheNodeidentityInfo bool) (nodeidentity.Identifier, error) {
	region, err := getMetadataRegion()
	if err != nil {
		return nil, fmt.Errorf("failed to get droplet region: %s", err)
	}

	doClient, err := NewCloud(region)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize digitalocean cloud: %s", err)
	}

	return &nodeIdentifier{
		doClient:     doClient,
		cache:        expirationcache.NewTTLStore(stringKeyFunc, cacheTTL),
		cacheEnabled: cacheNodeidentityInfo,
	}, nil
}

func getMetadataRegion() (string, error) {
	return getMetadata(dropletRegionMetadataURL)
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Run the component on a DigitalOcean Droplet, or test connectivity: curl http://169.254.169.254/metadata/v1/region.
  2. Check firewall/network policy allows access to the link-local metadata address 169.254.169.254.
  3. When running in containers, use host networking (--net=host) so the link-local address is reachable.
  4. Verify the DO metadata service status (status.digitalocean.com) for incidents and retry.

Example fix

// before: running identifier locally on a laptop
id, err := nodeidentity.New(true) // fails: no metadata service

// after: run inside a Droplet or inject region for tests
if os.Getenv("KOPS_DO_REGION") != "" {
    region = os.Getenv("KOPS_DO_REGION")
} else {
    region, err = getMetadataRegion()
}
Defensive patterns

Strategy: validation

Validate before calling

resp, err := http.Get("http://169.254.169.254/metadata/v1/region")
if err != nil || resp.StatusCode != http.StatusOK {
    return fmt.Errorf("not running on a DO Droplet or metadata blocked: err=%v", err)
}
resp.Body.Close()

Try / catch

id, err := nodeidentity.New(true)
if err != nil && strings.Contains(err.Error(), "failed to get droplet region") {
    return fmt.Errorf("run this component on a Droplet with access to 169.254.169.254: %w", err)
}

Prevention

When it happens

Trigger: Running kOps' DO nodeidentifier code on a machine that is not a DigitalOcean Droplet (laptop, CI runner, non-DO cloud); DO metadata service blocked by firewall/network policy; metadata endpoint returning non-200 or malformed region; IPv6-only networking where the link-local metadata address is unreachable.

Common situations: Local development/testing of kops against a DO cluster from off-cluster; network firewall (cloud firewall, nftables) blocking 169.254.169.254; DO metadata service incidents; running inside a container without host network access to the link-local address.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/6a92116ffa8394e6. Report an issue: GitHub.