argoproj/argo-workflows · error · ArgoError
BadRequest
BadRequest
Error message
templates.%s.script.image may not be empty
What it means
The `default` branch of the script-image check: if the current template base is neither a Workflow nor a WorkflowTemplate (e.g. a ClusterWorkflowTemplate or unknown base kind), the validator cannot consult templateDefaults, so an empty `script.image` is unconditionally rejected. Ensures every script template ends up with a resolvable container image.
Source
Thrown at workflow/validate/validate.go:974
if err != nil {
return errors.Errorf(errors.CodeBadRequest, "templates.%s.resource.manifest must be a valid yaml", tmpl.Name)
}
}
}
}
if tmpl.Script != nil {
if tmpl.Script.Image == "" {
switch baseTemplate := tmplCtx.GetCurrentTemplateBase().(type) {
case *wfv1.Workflow:
if baseTemplate.Spec.TemplateDefaults == nil || baseTemplate.Spec.TemplateDefaults.Script == nil || baseTemplate.Spec.TemplateDefaults.Script.Image == "" {
return errors.Errorf(errors.CodeBadRequest, "templates.%s.script.image may not be empty", tmpl.Name)
}
case *wfv1.WorkflowTemplate:
if baseTemplate.Spec.TemplateDefaults == nil || baseTemplate.Spec.TemplateDefaults.Script == nil || baseTemplate.Spec.TemplateDefaults.Script.Image == "" {
return errors.Errorf(errors.CodeBadRequest, "templates.%s.script.image may not be empty", tmpl.Name)
}
default:
return errors.Errorf(errors.CodeBadRequest, "templates.%s.script.image may not be empty", tmpl.Name)
}
}
}
// we don't validate tmpl.Plugin, because this is done by Plugin.UnmarshallJSON
if tmpl.ActiveDeadlineSeconds != nil {
if !intstr.IsValidIntOrArgoVariable(tmpl.ActiveDeadlineSeconds) && !placeholderGenerator.IsPlaceholder(tmpl.ActiveDeadlineSeconds.StrVal) {
return errors.Errorf(errors.CodeBadRequest, "templates.%s.activeDeadlineSeconds must be a positive integer > 0 or an argo variable", tmpl.Name)
}
if i, err := intstr.Int(tmpl.ActiveDeadlineSeconds); err == nil && i != nil && *i < 0 {
return errors.Errorf(errors.CodeBadRequest, "templates.%s.activeDeadlineSeconds must be a positive integer > 0 or an argo variable", tmpl.Name)
}
}
if tmpl.Parallelism != nil {
return errors.Errorf(errors.CodeBadRequest, "templates.%s.parallelism is only valid for steps and dag templates", tmpl.Name)
}
return nil
}
View on GitHub (pinned to 35bff19146)
Solutions
- Always set `script.image` explicitly on script templates referenced via ClusterWorkflowTemplate.
- Move the script template into a WorkflowTemplate/Workflow where templateDefaults can be consulted, and set defaults there.
- Check `tmplCtx.GetCurrentTemplateBase()` resolution if you believe the kind is wrong.
Example fix
// before script: source: echo hi // after script: image: alpine:3.19 source: echo hi
Defensive patterns
Strategy: validation
Validate before calling
if (tmpl.script && !tmpl.script.image) {
throw new Error('script.image must be explicit when base kind is not Workflow/WorkflowTemplate (e.g. ClusterWorkflowTemplate)');
} Type guard
function scriptImageExplicit(t) {
return !t.script || Boolean(t.script.image);
} Prevention
- Never rely on defaults for ClusterWorkflowTemplate-referenced script templates
- Make script.image a required field in your workflow authoring tooling
- Pin images explicitly for auditability
When it happens
Trigger: A script template without `image` validated against a base template kind other than Workflow/WorkflowTemplate — typically when templates come from ClusterWorkflowTemplates or the template context returns an unexpected type.
Common situations: Referencing a ClusterWorkflowTemplate that itself lacks a script image and has no defaults honored by this check; custom/older CRD kinds passing through validation.
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
- CodeBadRequest
- unable to parse node field selector '%s': %w
- containers must have at least one container
- malformed workflow template parameter "%s": valueFrom is nil
- ConfigMap '%s' needs to have the label %s: %s to load parame
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/cf021ce5412a336e.
Report an issue: GitHub.