{"record":{"id":"298981d92cf94100","repo":"hashicorp/nomad","slug":"io-reader-being-decoded-is-nil","errorCode":null,"errorMessage":"'io.Reader' being decoded is nil","messagePattern":"'io\\.Reader' being decoded is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"command/var.go","lineNumber":282,"sourceCode":"\n\t// Repeated keys will be converted into a slice\n\tif existingValue, ok := b.result[key]; ok {\n\t\tvar sliceValue []any\n\t\tif err := mapstructure.WeakDecode(existingValue, &sliceValue); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsliceValue = append(sliceValue, value)\n\t\tb.result[key] = sliceValue\n\t\treturn nil\n\t}\n\n\tb.result[key] = value\n\treturn nil\n}\n\nfunc (b *KVBuilder) addReader(r io.Reader) error {\n\tif r == nil {\n\t\treturn fmt.Errorf(\"'io.Reader' being decoded is nil\")\n\t}\n\n\tdec := json.NewDecoder(r)\n\t// While decoding JSON values, interpret the integer values as\n\t// `json.Number`s instead of `float64`.\n\tdec.UseNumber()\n\n\treturn dec.Decode(&b.result)\n}\n\n// handleCASError provides consistent output for operations that result in a\n// check-and-set error\nfunc handleCASError(err error, c VarUI) (handled bool) {\n\tui := c.GetConcurrentUI()\n\tif cErr, ok := errors.AsType[api.ErrCASConflict](err); ok {\n\t\tlastUpdate := \"\"\n\t\tif cErr.Conflict.ModifyIndex > 0 {\n\t\t\tlastUpdate = fmt.Sprintf(","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/var.go#L264-L300","documentation":"KVBuilder.addReader decodes JSON from an io.Reader into the result map. This error is thrown immediately when the reader passed in is nil, before any JSON decoding is attempted. It is a defensive guard against wiring mistakes where no input source was configured.","triggerScenarios":"Calling KVBuilder.addReader(nil) directly, or reaching it via Add(\"-\")/Add(\"key=@-\") paths where the configured reader (b.Stdin or an opened file handle) ended up nil.","commonSituations":"Programmatic construction of KVBuilder with a nil Stdin; a helper that returns (io.Reader, error) and a nil reader being passed through unchecked; variable shadowing leaving the reader unset.","solutions":["Ensure the reader passed to addReader (or KVBuilder.Stdin) is non-nil before the call","Check the code path that produces the reader — a failed os.Open or unset field — and handle its error/zero value first","Prefer the public Add API which pre-validates Stdin, rather than calling addReader directly"],"exampleFix":"// before\nvar r io.Reader // nil\nb.addReader(r)\n// after\nif r == nil { r = strings.NewReader(\"{}\") }\nb.addReader(r)","handlingStrategy":"type-guard","validationCode":"func nonNilReader(r io.Reader) io.Reader {\n\tif r == nil { return strings.NewReader(\"{}\") }\n\treturn r\n}","typeGuard":"func isNilReader(r io.Reader) bool {\n\tif r == nil { return true }\n\tif v := reflect.ValueOf(r); v.Kind() == reflect.Ptr && v.IsNil() { return true }\n\treturn false\n}","tryCatchPattern":null,"preventionTips":["Check readers for nil (including typed-nil pointers) before addReader/Add","Prefer the public Add API which pre-validates Stdin","Handle errors from helpers that return (io.Reader, error) instead of passing through nil"],"tags":["cli","json","nil-reader"],"backgroundTag":"nil-reader","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}