kubernetes/kops · error

unable to resolve image %q: %w

Error message

unable to resolve image %q: %w

What it means

After asserting the cloud is AWSCloud, karpenterRootDeviceName calls cloud.ResolveImage(image) to look up the AMI. When that AWS API lookup itself fails (network error, invalid image format, API error), the failure is wrapped with this message and returned.

Source

Thrown at upup/pkg/fi/cloudup/template_functions_karpenter.go:392

			DeviceName: rootDeviceName,
			EBS:        ebs,
			RootVolume: new(true),
		},
	}, nil
}

// karpenterRootDeviceName resolves the root device name of the InstanceGroup image, so
// that the generated block device mapping overrides the image's root volume rather than
// attaching an additional one. The name varies between images (/dev/xvda, /dev/sda1),
// so it has to come from the image itself.
func (tf *TemplateFunctions) karpenterRootDeviceName(image string) (string, error) {
	cloud, ok := tf.cloud.(awsup.AWSCloud)
	if !ok {
		return "", fmt.Errorf("expected an AWS cloud, got %T", tf.cloud)
	}
	resolved, err := cloud.ResolveImage(image)
	if err != nil {
		return "", fmt.Errorf("unable to resolve image %q: %w", image, err)
	}
	if resolved == nil {
		return "", fmt.Errorf("unable to resolve image %q: not found", image)
	}
	rootDeviceName := fi.ValueOf(resolved.RootDeviceName)
	if rootDeviceName == "" {
		return "", fmt.Errorf("image %q has no root device name", image)
	}
	return rootDeviceName, nil
}

func (tf *TemplateFunctions) buildKarpenterNodePool(ig *kops.InstanceGroup) (*karpenterNodePool, error) {
	labels, err := nodelabels.BuildNodeLabels(tf.Cluster, ig)
	if err != nil {
		return nil, fmt.Errorf("building node labels for %q: %w", ig.Name, err)
	}
	labels = karpenterNodePoolTemplateLabels(labels)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the image string is a valid AMI id, alias (owner/name), or name resolvable in the target region
  2. Check AWS credentials and that ec2:DescribeImages is allowed
  3. Retry kops update cluster if the failure was transient (API throttling/network)
  4. Inspect the wrapped inner error (%w) for the root cause

Example fix

// before
image: ami-nonexistent
// after
image: ami-0abcdef1234567890  # or a valid alias like 099720109477/ubuntu-jammy-22.04-amd64-server-*
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check the image resolves before rendering templates
cloud := tf.cloud.(awsup.AWSCloud)
if _, err := cloud.ResolveImage(image); err != nil {
	return fmt.Errorf("image %q cannot be resolved: %w", image, err)
}

Try / catch

if _, err := tf.karpenterRootDeviceName(image); err != nil {
	var resolveErr *fmt.WrapError
	if strings.Contains(err.Error(), "unable to resolve image") {
		// inspect wrapped cause: API/network/credential issue
		return fmt.Errorf("check AWS API access and image spec: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: cloud.ResolveImage returns an error for the given image string — e.g. malformed AMI name, AWS EC2 DescribeImages API error, throttling, or connectivity failure during template rendering for a Karpenter EC2NodeClass.

Common situations: Typo'd AMI name/alias in the instance group spec; AWS API outage or rate limiting during `kops update cluster`; credentials lacking ec2:DescribeImages permission; specifying an image in a region where it does not exist.

Related errors


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