{"record":{"id":"01213acd3b1dc8af","repo":"kubernetes/kops","slug":"error-rendering-addon-q-template-w","errorCode":null,"errorMessage":"error rendering addon %q template: %w","messagePattern":"error rendering addon %q template: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/bootstrapchannelbuilder/addonmanifest.go","lineNumber":92,"sourceCode":"}\n\nfunc (a *AddonManifest) Normalize(c *fi.CloudupContext) error {\n\tif a.addonSpec == nil {\n\t\treturn fmt.Errorf(\"addon spec is not configured for %q\", fi.ValueOf(a.Name))\n\t}\n\tif a.source == nil {\n\t\treturn fmt.Errorf(\"addon source is not configured for %q\", fi.ValueOf(a.Name))\n\t}\n\n\tmanifestBytes, err := fi.ResourceAsBytes(a.source)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error reading addon %q manifest: %v\", fi.ValueOf(a.Name), err)\n\t}\n\n\tif !a.skipRender && a.addonRenderer != nil {\n\t\tmanifestBytes, err = a.addonRenderer.RenderTemplate(fi.ValueOf(a.Location), manifestBytes, tasksVisibleToAddons(c.AllTasks()))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error rendering addon %q template: %w\", fi.ValueOf(a.Name), err)\n\t\t}\n\t}\n\n\tif !a.skipRemap {\n\t\tmanifestBytes, err = addonmanifests.RemapAddonManifest(a.addonSpec, a.modelContext, a.assetBuilder, manifestBytes, a.serviceAccounts)\n\t\tif err != nil {\n\t\t\tklog.Infof(\"invalid manifest: %s\", string(manifestBytes))\n\t\t\treturn fmt.Errorf(\"error remapping manifest %s: %v\", fi.ValueOf(a.Location), err)\n\t\t}\n\t}\n\n\tmanifestBytes = []byte(strings.TrimSpace(string(manifestBytes)))\n\n\tif a.buildPrune {\n\t\tif err := buildPruneDirectives(a.addonSpec, manifestBytes); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to configure pruning for %s: %w\", fi.ValueOf(a.addonSpec.Name), err)\n\t\t}\n\t}","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/bootstrapchannelbuilder/addonmanifest.go#L74-L110","documentation":"After reading the raw manifest bytes, AddonManifest.Normalize optionally renders the addon template through a.addonRenderer.RenderTemplate, passing the addon location and all tasks visible to addons. If template rendering fails (missing/unknown template variable, bad template syntax, task lookup issues), the error is wrapped with %w so the underlying template error is preserved and the addon name is included.","triggerScenarios":"Normalize runs (covered by the two TestAddonManifestNormalize* tests) with skipRender=false and addonRenderer non-nil, and RenderTemplate returns an error — typically an unresolvable template placeholder for the cluster/tasks context or a malformed template in the addon manifest.","commonSituations":"A custom addon template references a variable that is not among tasksVisibleToAddons(c.AllTasks()) or not exposed by the renderer; Go template syntax errors in a hand-written addon manifest; kOps upgrade changes the template context so an old template's field no longer exists.","solutions":["Read the wrapped cause (the %w chain) to identify the exact template/variable failure","Check every {{ ... }} placeholder in the addon manifest is supported by the renderer and resolvable from the tasks visible to addons","If this addon needs no templating, mark it as a raw source (skipRender path) instead of a template","If a kOps upgrade broke the template, update the addon manifest template to the new context/fields or pin the addon version","Run the failing addon's template render in isolation (go test in bootstrapchannelbuilder) to iterate quickly"],"exampleFix":"// before (template references unknown field)\nimage: {{ .NonExistentTask.Image }}\n// after\nimage: {{ .Image }}  // or a field exposed via tasksVisibleToAddons","handlingStrategy":"try-catch","validationCode":"// pre-check template placeholders against renderer-supported keys\nfor _, key := range extractTemplateKeys(manifestBytes) {\n    if !rendererSupports(key) {\n        return fmt.Errorf(\"unsupported template key %s in addon %s\", key, addonName)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := m.Normalize(ctx); err != nil {\n    var tmplErr error\n    if errors.As(err, &tmplErr) && strings.Contains(err.Error(), \"error rendering addon\") {\n        log.Printf(\"template failure for %s: %v\", name, err) // %w chain has root cause\n    }\n}","preventionTips":["Keep addon templates limited to fields exposed by the kOps template context","Test custom addon templates with the bootstrapchannelbuilder test harness","After kOps upgrades, re-render all custom addons and diff for context changes"],"tags":["addons","templates","bootstrap-channel"],"backgroundTag":"template-render-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}