kubernetes/kops · error
failed to get local-ipv4 address from ec2 metadata
Error message
failed to get local-ipv4 address from ec2 metadata: %w
What it means
After loading AWS config, GetMetadataLocalIP queries EC2 IMDS for local-ipv4 via getMetadata; any failure (timeout, 404, IMDSv2 token error) is wrapped with this message. nodeup needs this IP as the node's internal address (e.g. for server certs and systemd env files).
Solutions
- Ensure instance metadata service is reachable: curl -s -H 'X-aws-ec2-metadata-token: ...' http://169.254.169.254/latest/meta-data/local-ipv4 from the node
- Raise IMDSv2 hop limit: `aws ec2 modify-instance-metadata-options --instance-id <id> --http-put-response-hop-limit 2`
- Check iptables/host firewall and security setup for rules dropping 169.254.169.254 traffic
- Retry nodeup — transient IMDS failures during rolling updates often resolve; check EC2 service health/region status
Defensive patterns
Strategy: retry
Validate before calling
// precheck: token + local-ipv4 fetch before nodeup TOKEN=$(curl -sX PUT --max-time 2 'http://169.254.169.254/latest/api/token' -H 'X-aws-ec2-metadata-token-ttl-seconds: 60') curl -s --max-time 2 -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4 || echo "IMDS local-ipv4 unreachable"
Try / catch
ip, err := c.GetMetadataLocalIP(ctx)
if err != nil {
if strings.Contains(err.Error(), "local-ipv4") {
// transient IMDS failure: nodeup retries internally; on persistent failure raise hop limit / check firewall
return fmt.Errorf("IMDS local-ipv4 unavailable, verify metadata options and 169.254.169.254 egress: %w", err)
}
return err
} Prevention
- Set IMDSv2 hop limit to 2+ (required when nodeup runs in containers)
- Do not block 169.254.169.254 with host firewall or network policy
- Retry nodeup on transient IMDS failures during rolling updates
- Verify metadata works (curl) as a node bootstrap preflight
When it happens
Trigger: getMetadata(ctx, imds client, "local-ipv4") returns an error: IMDS unreachable (169.254.169.254 blocked), IMDSv2 token fetch fails due to hop limit, or the request times out during node bootstrap.
Common situations: Security groups/host firewall blocking link-local metadata; IMDSv2 hop limit of 1 when nodeup runs inside a container; transient IMDS throttling during mass rolling updates; non-EC2 environment misdetected as AWS.
Related errors
- failed to load AWS config
- error reading from AWS metadata service
- error reading instance-id from AWS metadata
- error reading local-ipv4 from AWS metadata
- failed to get instance metadata type
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/fd8e5df1da6fbaa5.
Report an issue: GitHub.
Appendix: source
Thrown at nodeup/pkg/model/context.go:600
// RunningOnAzure returns true if we are running on Azure
func (c *NodeupModelContext) RunningOnAzure() bool {
return c.CloudProvider() == kops.CloudProviderAzure
}
// GetMetadataLocalIP returns the local IP address read from metadata
func (c *NodeupModelContext) GetMetadataLocalIP(ctx context.Context) (string, error) {
var internalIP string
switch c.BootConfig.CloudProvider {
case kops.CloudProviderAWS:
config, err := awsconfig.LoadDefaultConfig(ctx)
if err != nil {
return "", fmt.Errorf("failed to load AWS config: %w", err)
}
metadata := imds.NewFromConfig(config)
localIPv4, err := getMetadata(ctx, metadata, "local-ipv4")
if err != nil {
return "", fmt.Errorf("failed to get local-ipv4 address from ec2 metadata: %w", err)
}
internalIP = localIPv4
case kops.CloudProviderHetzner:
client := hcloudmetadata.NewClient()
privateNetworksYaml, err := client.PrivateNetworks()
if err != nil {
return "", fmt.Errorf("failed to get private networks from hetzner cloud metadata: %w", err)
}
var privateNetworks []struct {
IP net.IP `json:"ip"`
AliasIPs []net.IP `json:"alias_ips"`
InterfaceNum int `json:"interface_num"`
MACAddress string `json:"mac_address"`
NetworkID int `json:"network_id"`
NetworkName string `json:"network_name"`
Network string `json:"network"`
Subnet string `json:"subnet"`View on GitHub (pinned to 4c8573c808)