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

  1. 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
  2. Recreate the workflow from a clean, validated manifest instead of patching the CR in place (`argo submit`, with `argo lint` first)
  3. Check for unsupported constructs in `transformation:` — data transformations only support a limited expression subset; move complex logic into a script template
  4. 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

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


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