argoproj/argo-workflows · error

template '%s' type is unknown

Error message

template '%s' type is unknown

What it means

During template resolution, ResolveTemplate fetches a template from a holder (workflow spec, workflow template, cluster workflow template, or stored template) and checks its type. If the resolved template's type is wfv1.TemplateTypeUnknown — i.e. the template exists but has no recognizable type (container, script, steps, dag, suspend, etc.) — resolution fails. This catches templates that are defined but effectively empty/unusable.

Source

Thrown at workflow/templateresolution/context.go:252

				}
				inlineResourceName = tmplRef.Name
			}
			err = tplCtx.workflow.SetStoredInlineTemplate(inlineScope, inlineResourceName, newTmpl)
			if err != nil {
				tplCtx.log.WithError(err).Error(ctx, "Failed to store the inline template")
			}
		}
		tmpl = newTmpl
	}

	// Update the template base of the context.
	newTmplCtx, err := tplCtx.WithTemplateHolder(ctx, tmplHolder)
	if err != nil {
		return nil, nil, false, err
	}

	if tmpl.GetType() == wfv1.TemplateTypeUnknown {
		return nil, nil, false, fmt.Errorf("template '%s' type is unknown", tmpl.Name)
	}

	return newTmplCtx, tmpl, templateStored, nil
}

// WithTemplateHolder creates new context with a template base of a given template holder.
func (tplCtx *TemplateContext) WithTemplateHolder(ctx context.Context, tmplHolder wfv1.TemplateReferenceHolder) (*TemplateContext, error) {
	tmplRef := tmplHolder.GetTemplateRef()
	if tmplRef != nil {
		tmplName := tmplRef.Name
		if tmplRef.ClusterScope {
			return tplCtx.WithClusterWorkflowTemplate(ctx, tmplName)
		}
		return tplCtx.WithWorkflowTemplate(ctx, tmplName)
	}
	return tplCtx.WithTemplateBase(tplCtx.tmplBase), nil
}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Give the referenced template a valid type body (container, script, steps, dag, suspend, etc.) in the WorkflowTemplate
  2. Verify the template name in templateRef/template points at the intended template (kubectl get workflowtemplate -o yaml)
  3. Re-apply the WorkflowTemplate CRD/version so fields deserialize correctly, then resubmit the workflow

Example fix

// before (WorkflowTemplate)
templates:
  - name: main
    {}
// after
templates:
  - name: main
    container:
      image: alpine
      command: [echo, hello]
Defensive patterns

Strategy: validation

Validate before calling

for _, t := range wt.Spec.Templates {
    if t.GetType() == wfv1.TemplateTypeUnknown {
        return fmt.Errorf("template %q in %s has no type body", t.Name, wt.Name)
    }
}

Type guard

func hasKnownTemplateType(t *wfv1.Template) bool {
    return t.GetType() != wfv1.TemplateTypeUnknown
}

Try / catch

wf, err := client.ArgoprojV1alpha1().Workflows(ns).Create(ctx, wf, metav1.CreateOptions{})
if err != nil && strings.Contains(err.Error(), "type is unknown") {
    // inspect the referenced WorkflowTemplate for an empty template body
}

Prevention

When it happens

Trigger: templateRef/template name resolves to a template whose spec lacks any type-defining field (no container, script, steps, dag, resource, suspend, data, http, plugin), e.g. an empty template {} in a WorkflowTemplate referenced via workflowTemplateRef or a stored template whose type could not be derived.

Common situations: Referencing the wrong template name in a WorkflowTemplate; a template with only metadata and no body; CRD/schema version mismatch where template fields fail to deserialize so type is lost; copy-pasted placeholder templates.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/71b7bf6091c72f0d. Report an issue: GitHub.