kubernetes/kops · error

error reading addon %q: %v

Error message

error reading addon %q: %v

What it means

After resolving the addon location to a URL, LoadClusterAddon reads the addon manifest bytes through the VFS context. Any ReadFile failure (not-found, permission denied, TLS/network errors, bad credentials) is wrapped as this error with the resolved URL and underlying cause.

Source

Thrown at pkg/clusteraddons/load.go:46

type ClusterAddon struct {
	Raw     string
	Objects kubemanifest.ObjectList
}

// LoadClusterAddon loads a set of objects from the specified VFS location
func LoadClusterAddon(vfsContext *vfs.VFSContext, location string) (*ClusterAddon, error) {
	u, err := url.Parse(location)
	if err != nil {
		return nil, fmt.Errorf("invalid addon location: %q", location)
	}

	// TODO: Should we support relative paths for "standard" addons?  See equivalent code in LoadChannel

	resolved := u.String()
	klog.V(2).Infof("Loading addon from %q", resolved)
	addonBytes, err := vfsContext.ReadFile(resolved)
	if err != nil {
		return nil, fmt.Errorf("error reading addon %q: %v", resolved, err)
	}
	addon, err := ParseClusterAddon(addonBytes)
	if err != nil {
		return nil, fmt.Errorf("error parsing addon %q: %v", resolved, err)
	}
	klog.V(4).Infof("Addon contents: %s", string(addonBytes))

	return addon, nil
}

// ParseClusterAddon parses a ClusterAddon object
func ParseClusterAddon(raw []byte) (*ClusterAddon, error) {
	objects, err := kubemanifest.LoadObjectsFrom(raw)
	if err != nil {
		return nil, fmt.Errorf("error parsing addon %v", err)
	}

	return &ClusterAddon{Raw: string(raw), Objects: objects}, nil

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the addon URL/exists: open the resolved location in a browser or curl it; fix the path if 404.
  2. Check VFS credentials and network access for the backend hosting the addon.
  3. Pin the addon location to a version-matched URL for your kops/Kubernetes version.

Example fix

// before
addon, err := LoadClusterAddon(vfs.Context, "https://addons.k8s.io/v1.28/networking.yaml") // 404
// after
addon, err := LoadClusterAddon(vfs.Context, "https://addons.k8s.io/stable/networking.yaml")
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight reachability check
if err := probeURL(resolvedLocation); err != nil {
  return fmt.Errorf("addon location unreachable before create: %v", err)
}

Try / catch

addon, err := LoadClusterAddon(vfs.Context, loc)
if err != nil {
  if strings.Contains(err.Error(), "error reading addon") {
    return retryWithBackoff(func() (*ClusterAddon, error) { return LoadClusterAddon(vfs.Context, loc) })
  }
  return err
}

Prevention

When it happens

Trigger: LoadClusterAddon called (from RunCreateCluster) with a location that resolves to a nonexistent file, a private bucket without credentials, a DNS/network failure, or an HTTP 404 on the addon URL.

Common situations: Kubernetes version-mismatched addon URLs that no longer exist upstream; offline/restricted networks during cluster creation; misconfigured S3/VFS credentials; typos in addon file names.

Related errors


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