kubernetes/kops · error

addon manifest did not have a spec

Error message

addon manifest %q did not have a spec

What it means

BootstrapChannelBuilder.Normalize assembles the channelsapi.Addons object listing every addon manifest in the channel. Before appending, it asserts each manifest's addonSpec is non-nil; a nil spec means the manifest was never properly built (its spec/hash pipeline never ran), so the channel would be incomplete and kOps fails with the addon's name in the message.

Solutions

  1. Ensure every addon goes through the AddonManifest build helper so addonSpec is populated before BootstrapChannelBuilder.Normalize runs
  2. Check task ordering/registration: the per-manifest Normalize must execute before the channel's Normalize; verify task dependencies/wiring
  3. If you added a new addon recently, diff against an existing addon's builder code to spot the missing spec wiring
  4. Re-run kops update with --dry-run and check the full error context to identify the failing addon name

Example fix

// before
a.addonManifests = append(a.addonManifests, &AddonManifest{Name: fi.PtrTo("my-addon"), source: res})
// after
m := buildAddonManifest(b, "my-addon", spec, res)
a.addonManifests = append(a.addonManifests, m) // spec wired via builder
Defensive patterns

Strategy: validation

Validate before calling

for _, m := range a.addonManifests {
    if m.addonSpec == nil {
        return fmt.Errorf("addon %s registered without spec; ensure AddonManifest.Normalize ran", fi.ValueOf(m.Name))
    }
}

Type guard

func manifestHasSpec(m *AddonManifest) bool { return m != nil && m.addonSpec != nil }

Prevention

When it happens

Trigger: Normalize runs over a.addonManifests and encounters an entry whose addonSpec field is nil — typically an AddonManifest registered in the builder whose Normalize (addonmanifest.go) never ran or never populated the spec, or one built manually in tests without a spec.

Common situations: A new addon added to the channel list without going through the buildAddonManifest pipeline; ordering issue where BootstrapChannelBuilder.Normalize runs before the manifest tasks are normalized; hand-written AddonManifest in custom builds.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at upup/pkg/fi/cloudup/bootstrapchannelbuilder/bootstrapchannel.go:60

	_ fi.CloudupHasDependencies = (*BootstrapChannel)(nil)
)

func (a *BootstrapChannel) GetDependencies(tasks map[string]fi.CloudupTask) []fi.CloudupTask {
	dependencies := make([]fi.CloudupTask, 0, len(a.addonManifests))
	for _, manifest := range a.addonManifests {
		dependencies = append(dependencies, manifest)
	}
	return dependencies
}

func (a *BootstrapChannel) Normalize(c *fi.CloudupContext) error {
	addonsObject := &channelsapi.Addons{}
	addonsObject.Kind = "Addons"
	addonsObject.ObjectMeta.Name = "bootstrap"

	for _, manifest := range a.addonManifests {
		if manifest.addonSpec == nil {
			return fmt.Errorf("addon manifest %q did not have a spec", fi.ValueOf(manifest.Name))
		}
		if manifest.addonSpec.ManifestHash == "" {
			return fmt.Errorf("addon %q manifest hash was not populated", fi.ValueOf(manifest.addonSpec.Name))
		}
		addonsObject.Spec.Addons = append(addonsObject.Spec.Addons, manifest.addonSpec)
	}

	if err := addonsObject.Verify(); err != nil {
		return err
	}

	addonsYAML, err := utils.YamlMarshal(addonsObject)
	if err != nil {
		return fmt.Errorf("error serializing addons yaml: %v", err)
	}

	a.Contents = fi.NewBytesResource(addonsYAML)
	return nil

View on GitHub (pinned to 4c8573c808)