argoproj/argo-workflows · error
no text to unmarshal
Error message
no text to unmarshal
What it means
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.
Source
Thrown at pkg/apis/workflow/v1alpha1/marshall.go:21
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sigs.k8s.io/yaml"
)
// MustUnmarshal is a utility function to unmarshall either a file, byte array, or string of JSON or YAMl into a object.
// 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
// v - a pointer to an object
func MustUnmarshal(text, v any) {
switch x := text.(type) {
case string:
MustUnmarshal([]byte(x), v)
case []byte:
if len(x) == 0 {
panic("no text to unmarshal")
}
switch x[0] {
case '@':
filename := string(x[1:])
y, err := os.ReadFile(filepath.Clean(filename))
if err != nil {
panic(fmt.Errorf("failed to read file %s: %w", filename, err))
}
MustUnmarshal(y, v)
case '{':
if err := json.Unmarshal(x, v); err != nil {
panic(fmt.Errorf("failed to unmarshal JSON %q: %w", string(x), err))
}
default:
if err := yaml.UnmarshalStrict(x, v); err != nil {
panic(fmt.Errorf("failed to unmarshal YAML %q: %w", string(x), err))
}
}View on GitHub (pinned to 35bff19146)
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
Example fix
// before
item := MustUnmarshal([]byte(os.Getenv("WF_SPEC")), &Item{})
// after
text := os.Getenv("WF_SPEC")
if text == "" {
panic("WF_SPEC env var is empty")
}
item := MustUnmarshal([]byte(text), &Item{}) Defensive patterns
Strategy: validation
Validate before calling
if text == nil || len(text.([]byte)) == 0 {
return fmt.Errorf("refusing MustUnmarshal: empty input")
}
MustUnmarshal(text, v) Try / catch
func() (item *Item, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("MustUnmarshal panicked: %v", r)
}
}()
MustUnmarshal(data, &item)
return item, nil
}() Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- duplicate synchronization item found
- failed to parse YAML from file %s: %w
- json: unknown field "%s"
- no workflow found in given files
- invalid TTL
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/535b5a6eeb511021.
Report an issue: GitHub.