kubernetes/kops · error

unable to fetch metadata: %w

Error message

unable to fetch metadata: %w

What it means

CreateToken (upup/pkg/fi/cloudup/openstack/openstackmetadata/authenticator.go:39) builds an authentication token from the instance's local metadata (ServerID). If GetLocalMetadata fails — because neither the config drive nor the metadata service could be read — the underlying error is wrapped with this message.

Source

Thrown at upup/pkg/fi/cloudup/openstack/openstackmetadata/authenticator.go:39

	"k8s.io/kops/pkg/bootstrap"
)

const OpenstackAuthenticationTokenPrefix = "x-openstack-id " //nolint:gosec // This is an authentication scheme prefix, not a credential.

type openstackAuthenticator struct {
}

var _ bootstrap.Authenticator = (*openstackAuthenticator)(nil)

func NewOpenstackAuthenticator() (bootstrap.Authenticator, error) {
	return &openstackAuthenticator{}, nil
}

func (o *openstackAuthenticator) CreateToken(body []byte) (string, error) {
	metadata, err := GetLocalMetadata()
	if err != nil {
		return "", fmt.Errorf("unable to fetch metadata: %w", err)
	}
	return OpenstackAuthenticationTokenPrefix + metadata.ServerID, nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the instance was booted with a config drive (nova boot --config-drive true or the flavor/image default) or that the metadata service (169.254.169.254) is reachable.
  2. Inspect the wrapped cause (%w) in the error chain to see whether it came from getFromConfigDrive or getFromMetadataService.
  3. Verify the metadata search order configured on the instance only contains 'configDrive' and 'metadataService'.
  4. Check network/security-group rules allow egress to the metadata service endpoint.

Example fix

// before
metadata, err := GetLocalMetadata()
if err != nil {
    return "", fmt.Errorf("unable to fetch metadata: %w", err)
}
// after — surface which source failed for faster diagnosis
metadata, err := GetLocalMetadata()
if err != nil {
    return "", fmt.Errorf("unable to fetch metadata (check config drive attachment and 169.254.169.254 reachability): %w", err)
}
Defensive patterns

Strategy: fallback

Validate before calling

// Check that at least one metadata source is plausibly available
if _, err := os.Stat("/dev/disk/by-label/" + "config-2"); err != nil {
    resp, err := http.Get("http://169.254.169.254/openstack/latest/meta_data.json")
    if err != nil || resp.StatusCode != http.StatusOK {
        return errors.New("neither config drive nor metadata service is reachable")
    }
}

Try / catch

token, err := authenticator.CreateToken(body)
if err != nil {
    var pathErr *fs.PathError
    if errors.As(err, &pathErr) {
        // config-drive read failed — fall back to metadata-service-only mode
    }
    return fmt.Errorf("token creation failed, metadata source unavailable: %w", err)
}

Prevention

When it happens

Trigger: GetLocalMetadata() returns an error: blkid cannot find a config-drive device, the config drive cannot be mounted/read, the metadata service HTTP request fails or returns non-200, or the configured search order contains invalid options.

Common situations: Node bootstrapping on an OpenStack VM where the config drive was not attached at instance creation; the nova metadata service is unreachable from the instance network; the instance was created without config_drive enabled while metadata service is firewalled.

Related errors


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