argoproj/argo-workflows · error
could not marshal data in transformation: %w
Error message
could not marshal data in transformation: %w
What it means
For a `data:` transformation template, the controller marshals the data source spec (artifactPaths, transformation expression, etc.) to JSON to pass it to `argoexec data` on the pod (workflow/controller/operator.go:3972). If `json.Marshal` fails — which for well-formed wfv1.Data should never happen, but can with corrupt or unexpectedly typed fields — the node is failed with 'could not marshal data in transformation: %w' and the underlying marshal error is wrapped.
Source
Thrown at workflow/controller/operator.go:3972
_, err = woc.createWorkflowPod(ctx, nodeName, []apiv1.Container{*mainCtr}, tmpl, &createWorkflowPodOpts{onExitPod: opts.onExitTemplate, executionDeadline: opts.executionDeadline})
if err != nil {
return woc.requeueIfTransientErr(ctx, err, node.Name)
}
return node, err
}
func (woc *wfOperationCtx) executeData(ctx context.Context, nodeName string, templateScope string, tmpl *wfv1.Template, orgTmpl wfv1.TemplateReferenceHolder, opts *executeTemplateOpts) (*wfv1.NodeStatus, error) {
node, err := woc.wf.GetNodeByName(nodeName)
if err != nil {
ctx, node = woc.initializeExecutableNode(ctx, nodeName, wfv1.NodeTypePod, templateScope, tmpl, orgTmpl, opts.boundaryID, wfv1.NodePending, opts.nodeFlag, false)
} else if !node.Pending() {
return node, nil
}
dataTemplate, err := json.Marshal(tmpl.Data)
if err != nil {
return node, fmt.Errorf("could not marshal data in transformation: %w", err)
}
mainCtr := woc.newExecContainer(common.MainContainerName, tmpl)
mainCtr.Command = append([]string{"argoexec", "data", string(dataTemplate)}, woc.getExecutorLogOpts(ctx)...)
_, err = woc.createWorkflowPod(ctx, nodeName, []apiv1.Container{*mainCtr}, tmpl, &createWorkflowPodOpts{onExitPod: opts.onExitTemplate, executionDeadline: opts.executionDeadline, includeScriptOutput: true})
if err != nil {
return woc.requeueIfTransientErr(ctx, err, node.Name)
}
return node, nil
}
func (woc *wfOperationCtx) executeSuspend(ctx context.Context, nodeName string, templateScope string, tmpl *wfv1.Template, orgTmpl wfv1.TemplateReferenceHolder, opts *executeTemplateOpts) (*wfv1.NodeStatus, error) {
node, err := woc.wf.GetNodeByName(nodeName)
if err != nil {
_, node = woc.initializeExecutableNode(ctx, nodeName, wfv1.NodeTypeSuspend, templateScope, tmpl, orgTmpl, opts.boundaryID, wfv1.NodePending, opts.nodeFlag, true)
woc.resolveInputFieldsForSuspendNode(ctx, node)
}View on GitHub (pinned to 35bff19146)
Solutions
- Inspect the wrapped json error to identify the offending field, then fix the `data:` section of the template so all fields are valid wfv1 types
- Recreate the workflow from a clean, validated manifest instead of patching the CR in place (`argo submit`, with `argo lint` first)
- Check for unsupported constructs in `transformation:` — data transformations only support a limited expression subset; move complex logic into a script template
- If a controller version regression is suspected, test the same spec on a neighboring Argo release and file an issue with the manifest
Example fix
# before (hand-patched CR, invalid types)
data:
transformation:
- expression: 42
# after
data:
source:
artifactPaths:
path: /tmp/data/*
transformation:
- expression: "filter(data, {# > 1})" Defensive patterns
Strategy: validation
Validate before calling
// pre-submit check that the data section serializes cleanly
if _, err := json.Marshal(tmpl.Data); err != nil {
return fmt.Errorf("invalid data template: %w", err)
} Type guard
func hasValidDataTemplate(tmpl *wfv1.Template) bool {
if tmpl.Data == nil {
return true
}
return tmpl.Data.Source.ArtifactPaths != nil && tmpl.Data.Transformation != nil
} Try / catch
// Go: recover is unnecessary here; just handle the returned error
node, err := woc.executeDataTransformation(...)
if err != nil {
if strings.Contains(err.Error(), "could not marshal data in transformation") {
woc.log.Error(ctx, "malformed data template", "err", err)
// fail node and surface the wrapped json error to the user
}
return err
} Prevention
- Never hand-patch Workflow CRs with kubectl; submit validated manifests via `argo submit`
- Use `argo lint` on any spec containing a `data:` block
- Keep transformation logic simple — move complex processing to script templates
- When generating specs via SDKs, use the typed builders rather than raw maps
When it happens
Trigger: A `data:` template whose `source`/`transformation` fields contain something json.Marshal cannot serialize (e.g. invalid field types injected through a hand-crafted or SDK-built spec, NaN-like values, or a spec object mutated at runtime); essentially only reachable via corrupt CR data or controller/SDK bugs since the API validation normally guarantees valid types.
Common situations: Directly PATCHing/creating Workflow CRs with kubectl and malformed data templates; custom controllers or scripts generating Workflow manifests; SDK versions with type-mismatched fields; trying to use expressions or templates not supported by the data transformation feature.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- failed to convert result to JSON "%s" expression: %w
- critical error; unable to find %s
- no Node found by the name of %s; wf.Status.Nodes=%+v
- no Retry Node found by the name of %s; wf.Status.Nodes=%+v
- expected node type %s, got %s
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/85c563e069f9e681.
Report an issue: GitHub.