GoogleContainerTools/skaffold · error
invalid component specified in custom template: %v
Error message
invalid component specified in custom template: %v
What it means
A template field resolved to a customTemplateTagger, i.e. a custom template component referenced itself (directly or transitively), which would cause infinite recursion. `EvaluateComponents` rejects this with this error naming the offending component.
Source
Thrown at pkg/skaffold/tag/custom_template.go:76
// missingkey=error throws error when map is indexed with an undefined key
tag, err := ExecuteCustomTemplate(t.Template.Option("missingkey=error"), customMap)
if err != nil {
return "", err
}
return tag, nil
}
// EvaluateComponents creates a custom mapping of component names to their tagger string representation.
func (t *customTemplateTagger) EvaluateComponents(ctx context.Context, image latest.Artifact) (map[string]string, error) {
taggers := map[string]Tagger{}
templateFields := GetTemplateFields(t.Template)
for _, field := range templateFields {
if v, ok := t.Components[field]; ok {
if _, ok := v.(*customTemplateTagger); ok {
return nil, fmt.Errorf("invalid component specified in custom template: %v", v)
}
taggers[field] = v
continue
}
switch field {
case "GIT":
gitTagger, _ := NewGitCommit("", "", false)
taggers[field] = gitTagger
case "DATE":
taggers[field] = NewDateTimeTagger("", "")
case "SHA":
taggers[field] = &ChecksumTagger{}
case "INPUT_DIGEST":
inputDigestTagger, _ := NewInputDigestTagger(t.RunCtx, graph.ToArtifactGraph(t.RunCtx.Artifacts()))
taggers[field] = inputDigestTagger
default:
return nil, fmt.Errorf("no tagger available for component %+v", field)
}View on GitHub (pinned to a1189de023)
Solutions
- Remove the nested custom-template component from the components map
- Use a primitive tagger component (DATE, SHA, GIT, LABEL, DIGEST, INPUT_DIGEST) for that field instead
- Refactor so the inner template's fields are expanded into the outer template directly
Example fix
// before: component map with recursion
components: {SUB: customTemplateTagger}
customTemplate: "{{.SUB}}-{{.SHA}}"
// after: reference primitives only
customTemplate: "{{.GIT}}-{{.SHA}}" Defensive patterns
Strategy: validation
Validate before calling
// ensure no component maps to a custom template tagger (no recursion)
for name, comp := range components {
if _, bad := comp.(*tag.CustomTemplateTagger); bad {
return fmt.Errorf("component %q must not be a custom template tagger", name)
}
} Type guard
func isPrimitiveTagger(t tag.Tagger) bool {
switch t.(type) {
case *tag.CustomTemplateTagger:
return false
default:
return true
}
} Prevention
- Never nest custom templates in the components map
- Compose templates from primitive components only (GIT, SHA, DATE...)
- Sketch the component graph to spot cycles before configuring
- Review skaffold.yaml tagger config in code review
When it happens
Trigger: `GenerateTag` calls `EvaluateComponents`; `GetTemplateFields` finds a field present in `t.Components`, but the value's concrete type is `*customTemplateTagger` — meaning a custom template component is nested inside another custom template's fields.
Common situations: Defining a custom tagger whose template includes a field mapped to another (or the same) custom template tagger in the components map; misconfigured `components` wiring that creates a cycle.
Related errors
- parsing template: %w
- no tagger available for component %+v
- executing template: %w
- value must be one of `always`, `missing`, or `never`
- CONFIG_REMOTE_REPO_CACHE_NOT_FOUND_ERR
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/c8b1f32546d67a18.
Report an issue: GitHub.