jmoiron/sqlx · error

JSONText: UnmarshalJSON on nil pointer

Error message

JSONText: UnmarshalJSON on nil pointer

What it means

JSONText.UnmarshalJSON implements json.Unmarshaler and requires a non-nil receiver, since it appends data into the existing slice. Calling it on a nil *JSONText would be unsafe/meaningless, so it returns this error. This typically surfaces when json.Unmarshal calls back into a nil pointer field.

Source

Thrown at types/types.go:73

// Value() validates the json format in the source, and returns an error if
// the json is not valid.  Scan does no validation.  JSONText additionally
// implements `Unmarshal`, which unmarshals the json within to an interface{}
type JSONText json.RawMessage

var emptyJSON = JSONText("{}")

// MarshalJSON returns the *j as the JSON encoding of j.
func (j JSONText) MarshalJSON() ([]byte, error) {
	if len(j) == 0 {
		return emptyJSON, nil
	}
	return j, nil
}

// UnmarshalJSON sets *j to a copy of data
func (j *JSONText) UnmarshalJSON(data []byte) error {
	if j == nil {
		return errors.New("JSONText: UnmarshalJSON on nil pointer")
	}
	*j = append((*j)[0:0], data...)
	return nil
}

// Value returns j as a value.  This does a validating unmarshal into another
// RawMessage.  If j is invalid json, it returns an error.
func (j JSONText) Value() (driver.Value, error) {
	var m json.RawMessage
	var err = j.Unmarshal(&m)
	if err != nil {
		return []byte{}, err
	}
	return []byte(j), nil
}

// Scan stores the src in *j.  No validation is done.
func (j *JSONText) Scan(src interface{}) error {

View on GitHub (pinned to 41dac167fd)

Solutions

  1. Initialize the JSONText before unmarshaling: use a value (JSONText) field or allocate with new(types.JSONText).
  2. Ensure the containing struct field is populated/allocated before json.Unmarshal runs.
  3. If scanning from SQL, prefer GzippedText/JSONText value semantics (var t types.JSONText).
  4. Wrap unmarshal and handle the error by allocating and retrying once.

Example fix

// before
var t *types.JSONText
json.Unmarshal(data, t) // nil pointer
// after
t := &types.JSONText{}
json.Unmarshal(data, t)
Defensive patterns

Strategy: type-guard

Validate before calling

func safeUnmarshalJSONText(data []byte, j **types.JSONText) error {
	if j == nil || *j == nil {
		*j = new(types.JSONText)
	}
	return json.Unmarshal(data, j)
}

Type guard

func nonNilJSONText(j *types.JSONText) *types.JSONText {
	if j == nil {
		return new(types.JSONText)
	}
	return j
}

Try / catch

if err := json.Unmarshal(data, &t); err != nil {
	if strings.Contains(err.Error(), "UnmarshalJSON on nil pointer") {
		t = &types.JSONText{}
		err = json.Unmarshal(data, &t)
	}
	return err
}

Prevention

When it happens

Trigger: json.Unmarshal(data, (*types.JSONText)(nil)); unmarshaling into a nil JSONText pointer field in a struct; JSON libraries calling UnmarshalJSON through a nil receiver.

Common situations: Struct field declared as *JSONText left nil by another decoder step; manual re-use of a pointer variable that was reset to nil; passing a nil pointer obtained from a failed previous decode.

Related errors


AI-assisted analysis of jmoiron/sqlx@41dac167fd (2026-09-03). Data as JSON: /api/errors/d216e6b8730e0d64. Report an issue: GitHub.