{"record":{"id":"b5216cc9bbc215bd","repo":"argoproj/argo-workflows","slug":"failed-to-unmarshal-container-args-w","errorCode":null,"errorMessage":"failed to unmarshal container args: %w","messagePattern":"failed to unmarshal container args: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"cmd/argoexec/commands/emissary.go","lineNumber":110,"sourceCode":"\t// Note it's important varRunArgo+\"/ctr/\" folder is writable by all, because multiple containers may want to\n\t// write to it with different users.\n\t// This also indicates we've started.\n\tif err = os.MkdirAll(varRunArgo+\"/ctr/\"+containerName, 0o777); err != nil {\n\t\treturn fmt.Errorf(\"failed to create ctr directory: %w\", err)\n\t}\n\n\tname, args := args[0], args[1:]\n\n\t// Check if args were offloaded to a file (for large args that exceed exec limit)\n\tif argsFile := os.Getenv(common.EnvVarContainerArgsFile); argsFile != \"\" {\n\t\tlogger.WithField(\"argsFile\", argsFile).Info(ctx, \"Reading container args from file\")\n\t\targsData, readErr := os.ReadFile(argsFile)\n\t\tif readErr != nil {\n\t\t\treturn fmt.Errorf(\"failed to read container args file %s: %w\", argsFile, readErr)\n\t\t}\n\t\tvar fileArgs []string\n\t\tif err = json.Unmarshal(argsData, &fileArgs); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal container args: %w\", err)\n\t\t}\n\t\targs = append(args, fileArgs...)\n\t\tlogger.WithField(\"count\", len(fileArgs)).Info(ctx, \"Loaded container args from file\")\n\n\t\t// Check for a large args and offload to file if needed\n\t\t// This avoids the exec() \"argument list too long\" error\n\t\t// Downstream programs should support @filename for parsing large args\n\t\tfor i := 0; i < len(args); i++ {\n\t\t\tif len(args[i]) > common.MaxEnvVarLen {\n\t\t\t\tfilePath := fmt.Sprintf(\"/tmp/argo_arg_%d.txt\", i)\n\t\t\t\tif err = os.WriteFile(filePath, []byte(args[i]), 0o644); err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"failed to write large arg %d to file: %w\", i, err)\n\t\t\t\t}\n\t\t\t\tlogger.WithFields(logging.Fields{\n\t\t\t\t\t\"argIndex\": i,\n\t\t\t\t\t\"size\":     len(args[i]),\n\t\t\t\t\t\"filePath\": filePath,\n\t\t\t\t}).Info(ctx, \"Offloaded large argument to file. Downstream program must support @filename syntax\")","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/cmd/argoexec/commands/emissary.go#L92-L128","documentation":"When container args were offloaded to a file (ARGO_CONTAINER_ARGS_FILE set), runEmissary reads the file and json.Unmarshal's it into []string. This error is thrown when the file contents are not a valid JSON array of strings. The args file is written by the controller as json.Marshal(container.Args), so invalid content means the offload contract between controller and executor is broken or the file is corrupted/truncated.","triggerScenarios":"The file at ARGO_CONTAINER_ARGS_FILE contains non-JSON data (empty file, YAML, a placeholder, an error page), contains a JSON object/array of non-strings, or is truncated so the JSON does not parse.","commonSituations":"ConfigMap size limit (1MiB) truncation or failed write; someone manually edited or replaced the ConfigMap; a tool rewrote the ConfigMap data with different formatting; version skew where an older controller wrote a non-JSON format a newer executor cannot parse; the ConfigMap key holds the container name but the executor read the wrong key.","solutions":["Inspect the file contents inside the pod (`kubectl exec <pod> -c <main> -- cat $ARGO_CONTAINER_ARGS_FILE`) and validate it is a JSON array of strings.","Re-run the workflow on a fresh pod: corrupted ConfigMaps are not repaired in place, a new pod gets a new one.","Align controller and executor versions — mismatched offload formats across upgrades are the usual cause.","Check the controller that wrote the ConfigMap (workflowpod.go) for a failed/partial write in its logs.","As a workaround, shrink the args below MaxEnvVarLen so args are passed via the pod spec directly, not the file."],"exampleFix":"// before: file contains garbage\nARGO_CONTAINER_ARGS_FILE=/argo/staging/args.json -> \"main\" (not JSON)\n// after: expected format written by the controller\n[\"--flag\",\"value\"]","handlingStrategy":"validation","validationCode":"// Validate the offloaded args file parses as a JSON string array before use:\nfunc validateArgsFile(path string) error {\n\tdata, err := os.ReadFile(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar args []string\n\tif err := json.Unmarshal(data, &args); err != nil {\n\t\treturn fmt.Errorf(\"args file %s is not a JSON string array: %w\", path, err)\n\t}\n\treturn nil\n}","typeGuard":"func isStringArray(v any) bool {\n\tarr, ok := v.([]any)\n\tif !ok {\n\t\treturn false\n\t}\n\tfor _, e := range arr {\n\t\tif _, ok := e.(string); !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","tryCatchPattern":"var fileArgs []string\nif err := json.Unmarshal(argsData, &fileArgs); err != nil {\n\tvar syntaxErr *json.SyntaxError\n\tswitch {\n\tcase errors.As(err, &syntaxErr):\n\t\tlog.Errorf(\"malformed args JSON at offset %d: %v\", syntaxErr.Offset, err)\n\tdefault:\n\t\tlog.Errorf(\"args JSON type mismatch: %v\", err)\n\t}\n\treturn err\n}","preventionTips":["Treat the offload ConfigMap as controller-owned — never edit it manually.","Verify JSON schema of offloaded data after any controller upgrade (integration tests).","Watch ConfigMap sizes against the 1MiB API-server limit for very large args.","Add a pre-submit lint step that estimates marshaled arg size."],"tags":["kubernetes","executor","json","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"}