kubernetes/kops · error
droplet metadata returned non-200 status code: %d
Error message
droplet metadata returned non-200 status code: %d
What it means
getMetadata fetches a URL from the DigitalOcean droplet metadata service (169.254.169.254). When the HTTP response status is not 200 OK, it aborts and wraps the status code in this error, meaning the metadata endpoint answered but could not serve the requested value.
Source
Thrown at pkg/nodeidentity/do/identify.go:107
if accessToken == "" {
return nil, errors.New("DIGITALOCEAN_ACCESS_TOKEN is required")
}
tokenSource := &TokenSource{AccessToken: accessToken}
oauthClient := oauth2.NewClient(context.TODO(), tokenSource)
return godo.NewClient(oauthClient), nil
}
func getMetadata(url string) (string, error) {
resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("failed to get metadata URL %s: %v", url, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("droplet metadata returned non-200 status code: %d", resp.StatusCode)
}
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read metadata information %s: %v", url, err)
}
return string(bodyBytes), nil
}
// IdentifyNode queries DigitalOcean for the node identity information.
func (i *nodeIdentifier) IdentifyNode(ctx context.Context, node *corev1.Node) (*nodeidentity.Info, error) {
providerID := node.Spec.ProviderID
if providerID == "" {
return nil, errors.New("provider ID cannot be empty")
}
const prefix = "digitalocean://"View on GitHub (pinned to 4c8573c808)
Solutions
- Check the exact status code in the error to identify whether it is 404 (bad path/key), 503 (retry later), or 403 (access blocked)
- Confirm the workload is actually running on a DigitalOcean droplet that supports the droplet metadata service
- Retry the operation; transient 5xx from the metadata service usually resolves
- Verify the metadata URL path matches the current DigitalOcean metadata API (e.g. /metadata/v1/region)
- Check for network interception of 169.254.169.254 (custom firewalls, link-local routing issues)
Defensive patterns
Strategy: retry
Validate before calling
resp, err := http.Get(metadataURL)
if err != nil { return err }
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("metadata unavailable: status %d", resp.StatusCode)
} Try / catch
body, err := getMetadata(url)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) || strings.Contains(err.Error(), "non-200") {
// retry with backoff or fall back to cached region
}
} Prevention
- Only invoke DO metadata lookups on hosts that are DigitalOcean droplets
- Add retry with exponential backoff for transient 5xx responses
- Cache the last-known region value as a fallback
- Monitor/health-check 169.254.169.254 reachability on startup
When it happens
Trigger: The metadata service returns 404 (requested metadata key not exposed), 503 (metadata service temporarily unavailable), or 403 on an internal link from within a droplet via getMetadataRegion.
Common situations: Running on a non-DigitalOcean host where the metadata endpoint exists but lacks the key; DigitalOcean metadata service degraded/unavailable; wrong metadata path constructed; proxy or firewall intercepting link-local requests.
Related errors
- failed to read metadata information %s: %v
- failed to load AWS config: %w
- failed to get local-ipv4 address from ec2 metadata: %w
- error querying DigitalOcean droplet ID: %w
- downloading %q: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/3f03be689bd62776.
Report an issue: GitHub.