{"record":{"id":"85c563e069f9e681","repo":"argoproj/argo-workflows","slug":"could-not-marshal-data-in-transformation-w","errorCode":null,"errorMessage":"could not marshal data in transformation: %w","messagePattern":"could not marshal data in transformation: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/controller/operator.go","lineNumber":3972,"sourceCode":"\t_, err = woc.createWorkflowPod(ctx, nodeName, []apiv1.Container{*mainCtr}, tmpl, &createWorkflowPodOpts{onExitPod: opts.onExitTemplate, executionDeadline: opts.executionDeadline})\n\tif err != nil {\n\t\treturn woc.requeueIfTransientErr(ctx, err, node.Name)\n\t}\n\n\treturn node, err\n}\n\nfunc (woc *wfOperationCtx) executeData(ctx context.Context, nodeName string, templateScope string, tmpl *wfv1.Template, orgTmpl wfv1.TemplateReferenceHolder, opts *executeTemplateOpts) (*wfv1.NodeStatus, error) {\n\tnode, err := woc.wf.GetNodeByName(nodeName)\n\tif err != nil {\n\t\tctx, node = woc.initializeExecutableNode(ctx, nodeName, wfv1.NodeTypePod, templateScope, tmpl, orgTmpl, opts.boundaryID, wfv1.NodePending, opts.nodeFlag, false)\n\t} else if !node.Pending() {\n\t\treturn node, nil\n\t}\n\n\tdataTemplate, err := json.Marshal(tmpl.Data)\n\tif err != nil {\n\t\treturn node, fmt.Errorf(\"could not marshal data in transformation: %w\", err)\n\t}\n\n\tmainCtr := woc.newExecContainer(common.MainContainerName, tmpl)\n\tmainCtr.Command = append([]string{\"argoexec\", \"data\", string(dataTemplate)}, woc.getExecutorLogOpts(ctx)...)\n\t_, err = woc.createWorkflowPod(ctx, nodeName, []apiv1.Container{*mainCtr}, tmpl, &createWorkflowPodOpts{onExitPod: opts.onExitTemplate, executionDeadline: opts.executionDeadline, includeScriptOutput: true})\n\tif err != nil {\n\t\treturn woc.requeueIfTransientErr(ctx, err, node.Name)\n\t}\n\n\treturn node, nil\n}\n\nfunc (woc *wfOperationCtx) executeSuspend(ctx context.Context, nodeName string, templateScope string, tmpl *wfv1.Template, orgTmpl wfv1.TemplateReferenceHolder, opts *executeTemplateOpts) (*wfv1.NodeStatus, error) {\n\tnode, err := woc.wf.GetNodeByName(nodeName)\n\tif err != nil {\n\t\t_, node = woc.initializeExecutableNode(ctx, nodeName, wfv1.NodeTypeSuspend, templateScope, tmpl, orgTmpl, opts.boundaryID, wfv1.NodePending, opts.nodeFlag, true)\n\t\twoc.resolveInputFieldsForSuspendNode(ctx, node)\n\t}","sourceCodeStart":3954,"sourceCodeEnd":3990,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/controller/operator.go#L3954-L3990","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before (hand-patched CR, invalid types)\ndata:\n  transformation:\n    - expression: 42\n# after\ndata:\n  source:\n    artifactPaths:\n      path: /tmp/data/*\n  transformation:\n    - expression: \"filter(data, {# > 1})\"","handlingStrategy":"validation","validationCode":"// pre-submit check that the data section serializes cleanly\nif _, err := json.Marshal(tmpl.Data); err != nil {\n    return fmt.Errorf(\"invalid data template: %w\", err)\n}","typeGuard":"func hasValidDataTemplate(tmpl *wfv1.Template) bool {\n    if tmpl.Data == nil {\n        return true\n    }\n    return tmpl.Data.Source.ArtifactPaths != nil && tmpl.Data.Transformation != nil\n}","tryCatchPattern":"// Go: recover is unnecessary here; just handle the returned error\nnode, err := woc.executeDataTransformation(...)\nif err != nil {\n    if strings.Contains(err.Error(), \"could not marshal data in transformation\") {\n        woc.log.Error(ctx, \"malformed data template\", \"err\", err)\n        // fail node and surface the wrapped json error to the user\n    }\n    return err\n}","preventionTips":["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"],"tags":["argo-workflows","data-transformation","json-marshal","controller"],"backgroundTag":"json-marshal-failed","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}