{"record":{"id":"f8c0e2aad53b506f","repo":"argoproj/argo-workflows","slug":"failed-to-unmarshal-template-w","errorCode":null,"errorMessage":"failed to unmarshal template: %w","messagePattern":"failed to unmarshal template: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"cmd/argoexec/commands/emissary.go","lineNumber":160,"sourceCode":"\t\t\t// to supervisor pre-main setup rather than the user command.\n\t\t\t// The process exit code (not just the exitcode file) must carry\n\t\t\t// the sentinel, because inferFailedReason keys off the container's\n\t\t\t// terminated exit code; wrap so main propagates 65 while keeping\n\t\t\t// waitErr's message.\n\t\t\texitCode = common.ExitCodeSupervisorPreMainFailure\n\t\t\tlogger.WithError(waitErr).Error(ctx, \"supervisor failed before main container started\")\n\t\t\treturn argoerrors.NewExitErrWithCause(exitCode, waitErr)\n\t\t}\n\t}\n\n\tdata, err := readTemplate()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read template: %w\", err)\n\t}\n\n\ttemplate := &wfv1.Template{}\n\tif err = json.Unmarshal(data, template); err != nil {\n\t\treturn fmt.Errorf(\"failed to unmarshal template: %w\", err)\n\t}\n\n\t// In init-less pod mode, main can't use the legacy per-artifact\n\t// SubPath bind mount (kubelet races the supervisor's write). The\n\t// input-artifacts volume is mounted whole at /argo/inputs/artifacts\n\t// and the emissary symlinks each input artifact into its expected\n\t// path once supervisor has finished writing (guaranteed by the\n\t// ready-marker wait above). Only `main` runs this — ContainerSet\n\t// children and sidecars don't get artifact paths symlinked in.\n\tif waitForReady && containerName == common.MainContainerName {\n\t\tif stageErr := stageInputArtifacts(ctx, template); stageErr != nil {\n\t\t\t// As above: propagate the sentinel as the process exit code so\n\t\t\t// inferFailedReason attributes this to supervisor pre-main setup.\n\t\t\texitCode = common.ExitCodeSupervisorPreMainFailure\n\t\t\tlogger.WithError(stageErr).Error(ctx, \"failed to stage input artifacts before main container started\")\n\t\t\treturn argoerrors.NewExitErrWithCause(exitCode, stageErr)\n\t\t}\n\t}","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/cmd/argoexec/commands/emissary.go#L142-L178","documentation":"After successfully reading the template source (file or ARGO_TEMPLATE env), runEmissary json.Unmarshal's it into a wfv1.Template. This error is thrown when the bytes are not valid JSON or are not structurally a valid Template (wrong types, e.g. a string where an object is expected). Emissary cannot determine ContainerSet dependencies or input artifacts, so the pod fails before the user command runs.","triggerScenarios":"ARGO_TEMPLATE env value corrupted/truncated (exceeding env var limits, bad offload sentinel resolution); /var/run/argo/template partially written and read concurrently by emissary; a controller/executor version mismatch where one side marshals a schema the other cannot decode; the offloaded template chunk in the ConfigMap was modified or assembled out of order.","commonSituations":"Oversized templates offloaded to a ConfigMap and reassembled incorrectly after manual ConfigMap edits; upgrading Argo between versions with schema changes; custom templates injected via podspec patches that emit YAML not JSON; a race in a patched init-less layout reading the file while the supervisor is still writing it.","solutions":["Dump the actual bytes (`kubectl exec <pod> -c main -- cat /var/run/argo/template` or `echo $ARGO_TEMPLATE | base64 -d` if applicable) and validate the JSON.","Re-run the workflow to get a freshly written template; do not hand-edit the ConfigMap/offload data.","Align controller and executor versions (schema/marshal mismatches across upgrades).","Check controller logs for template env-offload errors (common.ResolveTemplateEnvValue path) if ARGO_TEMPLATE uses the offload sentinel.","If the template is legitimately huge, split it (smaller templates, fewer inline fields) to stay within env-var size limits."],"exampleFix":"// before: ARGO_TEMPLATE truncated mid-object\nARGO_TEMPLATE='{\"name\":\"main\",\"inputs\":{\"artifacts\":[{\"name\":\"a'\n// after: controller offloads oversized template to ConfigMap and sets sentinel,\n// readTemplate resolves it via common.ResolveTemplateEnvValue\nARGO_TEMPLATE='offload:/argo/config/ARGO_TEMPLATE'","handlingStrategy":"validation","validationCode":"// Validate template bytes decode into wfv1.Template before relying on them:\nfunc validateTemplateJSON(data []byte) error {\n\tvar t wfv1.Template\n\tif err := json.Unmarshal(data, &t); err != nil {\n\t\treturn fmt.Errorf(\"template payload invalid: %w\", err)\n\t}\n\tif t.Name == \"\" {\n\t\treturn fmt.Errorf(\"template payload decoded but has no name — wrong schema?\")\n\t}\n\treturn nil\n}","typeGuard":"func isJSONOrArray(b []byte) bool {\n\tvar v any\n\tif err := json.Unmarshal(b, &v); err != nil {\n\t\treturn false\n\t}\n\tswitch v.(type) {\n\tcase map[string]any, []any:\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"template := &wfv1.Template{}\nif err := json.Unmarshal(data, template); err != nil {\n\tvar ute *json.UnmarshalTypeError\n\tif errors.As(err, &ute) {\n\t\tlogger.WithError(err).Errorf(ctx, \"template schema mismatch at %s (offset %d) — controller/executor version skew?\", ute.Field, ute.Offset)\n\t}\n\treturn fmt.Errorf(\"failed to unmarshal template: %w\", err)\n}","preventionTips":["Do not hand-edit offloaded template ConfigMaps; regenerate by re-running the workflow.","Test controller→executor template handoff after every upgrade (version-skew matrix).","Keep templates modest in size so env-var offload/sentinel resolution is rarely exercised.","Never inject YAML into ARGO_TEMPLATE — it must be JSON.","Write the template file atomically (temp file + rename) in any custom writer to avoid torn reads."],"tags":["json","executor","schema","configmap","argo-workflows"],"backgroundTag":"json-unmarshal-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"}