{"record":{"id":"535b5a6eeb511021","repo":"argoproj/argo-workflows","slug":"no-text-to-unmarshal","errorCode":null,"errorMessage":"no text to unmarshal","messagePattern":"no text to unmarshal","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/apis/workflow/v1alpha1/marshall.go","lineNumber":21,"sourceCode":"import (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"sigs.k8s.io/yaml\"\n)\n\n// MustUnmarshal is a utility function to unmarshall either a file, byte array, or string of JSON or YAMl into a object.\n// text - a byte array or string, if starts with \"@\" it assumed to be a file and read from disk, is starts with \"{\" assumed to be JSON, otherwise assumed to be YAML\n// v - a pointer to an object\nfunc MustUnmarshal(text, v any) {\n\tswitch x := text.(type) {\n\tcase string:\n\t\tMustUnmarshal([]byte(x), v)\n\tcase []byte:\n\t\tif len(x) == 0 {\n\t\t\tpanic(\"no text to unmarshal\")\n\t\t}\n\t\tswitch x[0] {\n\t\tcase '@':\n\t\t\tfilename := string(x[1:])\n\t\t\ty, err := os.ReadFile(filepath.Clean(filename))\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"failed to read file %s: %w\", filename, err))\n\t\t\t}\n\t\t\tMustUnmarshal(y, v)\n\t\tcase '{':\n\t\t\tif err := json.Unmarshal(x, v); err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"failed to unmarshal JSON %q: %w\", string(x), err))\n\t\t\t}\n\t\tdefault:\n\t\t\tif err := yaml.UnmarshalStrict(x, v); err != nil {\n\t\t\t\tpanic(fmt.Errorf(\"failed to unmarshal YAML %q: %w\", string(x), err))\n\t\t\t}\n\t\t}","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/pkg/apis/workflow/v1alpha1/marshall.go#L3-L39","documentation":"MustUnmarshal is a helper in pkg/apis/workflow/v1alpha1/marshall.go that unmarshals YAML/JSON text into a value, supporting string/[]byte input and '@filename' file references. It panics with \"no text to unmarshal\" when given an empty []byte, because there is nothing to parse. It is intended for call sites where the input is known-good (tests, codegen); a panic signals a programming bug, not a runtime condition.","triggerScenarios":"Calling MustUnmarshal with an empty string coerced to []byte (len==0), e.g. MustUnmarshal([]byte(\"\"), &item), or a variable that was expected to hold YAML/JSON but is empty.","commonSituations":"Test fixtures where a heredoc/env variable/secret came back empty; reading config that failed silently upstream and passed an empty slice; tests like TestItem_GetMapVal/GetListVal/GetStrVal passing blank input by mistake.","solutions":["Verify the text argument is non-empty before calling MustUnmarshal; log/inspect the source of the string","Use the error-returning variant (unmarshal helper in the same file) if the input can legitimately be empty","Guard the call site: if len(data)==0 { initialize v with defaults instead of unmarshalling }","If loading from a file via '@path', confirm the file exists and is non-empty"],"exampleFix":"// before\nitem := MustUnmarshal([]byte(os.Getenv(\"WF_SPEC\")), &Item{})\n// after\ntext := os.Getenv(\"WF_SPEC\")\nif text == \"\" {\n    panic(\"WF_SPEC env var is empty\")\n}\nitem := MustUnmarshal([]byte(text), &Item{})","handlingStrategy":"validation","validationCode":"if text == nil || len(text.([]byte)) == 0 {\n    return fmt.Errorf(\"refusing MustUnmarshal: empty input\")\n}\nMustUnmarshal(text, v)","typeGuard":null,"tryCatchPattern":"func() (item *Item, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"MustUnmarshal panicked: %v\", r)\n        }\n    }()\n    MustUnmarshal(data, &item)\n    return item, nil\n}()","preventionTips":["Never pass env-var or config-derived text without an emptiness check","Prefer error-returning unmarshal helpers for untrusted input; reserve Must* for literals","In tests, assert fixture strings are non-empty before use"],"tags":["panic","yaml","unmarshal","go"],"backgroundTag":"empty-input-unmarshal-panic","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"}