micro/go-micro · error
changeset is nil
Error message
changeset is nil
What it means
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.
Source
Thrown at config/reader/json/json.go:64
b, err := j.json.Encode(merged)
if err != nil {
return nil, err
}
cs := &source.ChangeSet{
Timestamp: time.Now(),
Data: b,
Source: "json",
Format: j.json.String(),
}
cs.Checksum = cs.Sum()
return cs, nil
}
func (j *jsonReader) Values(ch *source.ChangeSet) (reader.Values, error) {
if ch == nil {
return nil, errors.New("changeset is nil")
}
if ch.Format != "json" {
return nil, errors.New("unsupported format")
}
return newValues(ch)
}
func (j *jsonReader) String() string {
return "json"
}
// NewReader creates a json reader.
func NewReader(opts ...reader.Option) reader.Reader {
options := reader.NewOptions(opts...)
return &jsonReader{
json: json.NewEncoder(),
opts: options,
}View on GitHub (pinned to 24529f1404)
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.
Example fix
// before
cs, _ := src.Read()
vals, _ := reader.Values(cs) // panics/errors if cs == nil
// after
cs, err := src.Read()
if err != nil || cs == nil {
return fmt.Errorf("source returned no changeset: %w", err)
}
vals, err := reader.Values(cs) Defensive patterns
Strategy: validation
Validate before calling
cs, err := src.Read()
if err != nil {
return err
}
if cs == nil {
return errors.New("source returned nil changeset")
}
vals, err := rdr.Values(cs) Type guard
func validChangeSet(ch *source.ChangeSet) bool { return ch != nil && ch.Format != "" } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/e5f4514c1eb14f08.
Report an issue: GitHub.