{"record":{"id":"e5f4514c1eb14f08","repo":"micro/go-micro","slug":"changeset-is-nil","errorCode":null,"errorMessage":"changeset is nil","messagePattern":"changeset is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"config/reader/json/json.go","lineNumber":64,"sourceCode":"\tb, err := j.json.Encode(merged)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcs := &source.ChangeSet{\n\t\tTimestamp: time.Now(),\n\t\tData:      b,\n\t\tSource:    \"json\",\n\t\tFormat:    j.json.String(),\n\t}\n\tcs.Checksum = cs.Sum()\n\n\treturn cs, nil\n}\n\nfunc (j *jsonReader) Values(ch *source.ChangeSet) (reader.Values, error) {\n\tif ch == nil {\n\t\treturn nil, errors.New(\"changeset is nil\")\n\t}\n\tif ch.Format != \"json\" {\n\t\treturn nil, errors.New(\"unsupported format\")\n\t}\n\treturn newValues(ch)\n}\n\nfunc (j *jsonReader) String() string {\n\treturn \"json\"\n}\n\n// NewReader creates a json reader.\nfunc NewReader(opts ...reader.Option) reader.Reader {\n\toptions := reader.NewOptions(opts...)\n\treturn &jsonReader{\n\t\tjson: json.NewEncoder(),\n\t\topts: options,\n\t}","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/config/reader/json/json.go#L46-L82","documentation":"The JSON config reader's Values method turns a source.ChangeSet into reader.Values. It first nil-checks the changeset: if ch is nil it returns \"changeset is nil\". This protects the reader from dereferencing a nil changeset, which would otherwise panic inside newValues. It indicates the caller passed no changeset at all, usually because an earlier source.Read produced (nil, nil) or a nil was propagated unchecked.","triggerScenarios":"Calling jsonReader.Values(nil) directly, or wiring a source/reader pipeline where source.Read returned a nil ChangeSet with a nil error and the result was passed to Values unchecked.","commonSituations":"Custom source implementations that return nil changesets on success; config code paths that skip the nil check on a Read result; tests constructing readers and passing nil to check behavior.","solutions":["Check the ChangeSet for nil after source.Read before calling Values.","Fix any custom source whose Read returns (nil, nil); it must return a valid ChangeSet or an error.","If the source genuinely has no data, return an empty ChangeSet with correct Format instead of nil.","Wrap the Read->Values sequence in a helper that validates inputs once."],"exampleFix":"// before\ncs, _ := src.Read()\nvals, _ := reader.Values(cs) // panics/errors if cs == nil\n// after\ncs, err := src.Read()\nif err != nil || cs == nil {\n    return fmt.Errorf(\"source returned no changeset: %w\", err)\n}\nvals, err := reader.Values(cs)","handlingStrategy":"validation","validationCode":"cs, err := src.Read()\nif err != nil {\n    return err\n}\nif cs == nil {\n    return errors.New(\"source returned nil changeset\")\n}\nvals, err := rdr.Values(cs)","typeGuard":"func validChangeSet(ch *source.ChangeSet) bool { return ch != nil && ch.Format != \"\" }","tryCatchPattern":null,"preventionTips":["Never ignore the error from source.Read — a nil changeset usually means a swallowed error.","Audit custom sources to ensure Read never returns (nil, nil).","Validate changesets once in a shared helper before dispatching to readers.","Add a unit test asserting your source returns non-nil changesets on success."],"tags":["config","reader","json","nil-check","go"],"backgroundTag":"nil-changeset","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}