kubernetes/kops · error

error reading addons from %q: %v

Error message

error reading addons from %q: %v

What it means

LoadAddons reads the addons channel YAML from a VFS location (local path, s3, HTTP, etc.) and wraps any read failure. This is a fetch-level error: the addons manifest content could not be retrieved at all, before any parsing happens.

Source

Thrown at channels/pkg/channels/addons.go:42

	"github.com/blang/semver/v4"
	"k8s.io/klog/v2"
	"k8s.io/kops/channels/pkg/api"
	"k8s.io/kops/pkg/kubemanifest"
	"k8s.io/kops/upup/pkg/fi/utils"
	"k8s.io/kops/util/pkg/vfs"
)

type Addons struct {
	ChannelName     string
	ChannelLocation url.URL
	APIObject       *api.Addons
}

func LoadAddons(vfsContext *vfs.VFSContext, name string, location *url.URL) (*Addons, error) {
	klog.V(2).Infof("Loading addons channel from %q", location)
	data, err := vfsContext.ReadFile(location.String())
	if err != nil {
		return nil, fmt.Errorf("error reading addons from %q: %v", location, err)
	}

	return ParseAddons(name, location, data)
}

func ParseAddons(name string, location *url.URL, data []byte) (*Addons, error) {
	configString := strings.TrimSpace(string(data))

	objects, err := kubemanifest.LoadObjectsFrom([]byte(configString))
	if err != nil {
		return nil, fmt.Errorf("error parsing addons or manifest: %v", err)
	}

	apiObject := &api.Addons{}
	if len(objects) == 0 {
		// No objects (empty, whitespace, or comment-only content): nothing to apply.
	} else if gvk := objects[0].GroupVersionKind(); gvk.Kind == "Addons" && gvk.Group == "" && gvk.Version == "" {
		// Reuse the document already parsed by LoadObjectsFrom instead of parsing it again.

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Verify the addons location URL/protocol and that the object exists (aws s3 ls / curl the URL).
  2. Fix cloud credentials for the storage backend (S3/GCS) hosting the channel.
  3. Re-upload the addons file or point the cluster spec at a valid channel (e.g. the default kops addons location).
  4. Check VFS base path flags so relative locations resolve correctly.

Example fix

# before: cluster spec
addons:
- manifest: s3://my-bucket/addons/typo-name.yaml
# after
addons:
- manifest: s3://my-bucket/addons/networking.amazon-vpc-routed-eni.yaml
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(addonsLocation)
if err != nil || u.String() == "" {
	return fmt.Errorf("invalid addons location: %q", addonsLocation)
}
// for s3: pre-check object existence, e.g. aws s3 ls s3://bucket/path/addons.yaml

Try / catch

addons, err := channels.LoadAddons(vfsContext, name, location)
if err != nil {
	if strings.Contains(err.Error(), "error reading addons") {
		return fmt.Errorf("check addons URL %q and storage credentials: %w", location, err)
	}
	return err
}

Prevention

When it happens

Trigger: LoadAddons(name, location) -> vfsContext.ReadFile(location.String()) fails: file does not exist, S3/GCS object missing or access denied, bad URL scheme, network timeout, or malformed VFS base path.

Common situations: Typo in the addons manifest URL; S3 credentials not configured; offline environment; channel file deleted or renamed after the cluster spec referenced it; kops upgrade changing default channel paths.

Related errors


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