grpc/grpc-go · error

nil receiver passed to UnmarshalJSON

Error message

nil receiver passed to UnmarshalJSON

What it means

codes.Code implements json.Unmarshaler (codes.go:225). If UnmarshalJSON is invoked on a nil *Code receiver — i.e. json.Unmarshal into a nil *Code — it returns this error instead of panicking on the subsequent *c = ... assignment. JSON null is handled separately as a no-op.

Source

Thrown at codes/codes.go:233

	`"ABORTED"`:             Aborted,
	`"OUT_OF_RANGE"`:        OutOfRange,
	`"UNIMPLEMENTED"`:       Unimplemented,
	`"INTERNAL"`:            Internal,
	`"UNAVAILABLE"`:         Unavailable,
	`"DATA_LOSS"`:           DataLoss,
	`"UNAUTHENTICATED"`:     Unauthenticated,
}

// UnmarshalJSON unmarshals b into the Code.
func (c *Code) UnmarshalJSON(b []byte) error {
	// From json.Unmarshaler: By convention, to approximate the behavior of
	// Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte("null")) as
	// a no-op.
	if string(b) == "null" {
		return nil
	}
	if c == nil {
		return fmt.Errorf("nil receiver passed to UnmarshalJSON")
	}

	if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil {
		if ci >= _maxCode {
			return fmt.Errorf("invalid code: %d", ci)
		}

		*c = Code(ci)
		return nil
	}

	if jc, ok := strToCode[string(b)]; ok {
		*c = jc
		return nil
	}
	return fmt.Errorf("invalid code: %q", string(b))
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Allocate the receiver before unmarshalling: c := new(codes.Code); json.Unmarshal(data, c).
  2. Unmarshal into a non-pointer codes.Code value or a wrapper struct with an allocated field.
  3. Use json.NewDecoder and ensure the target is addressable and non-nil.

Example fix

// before
var c *codes.Code
json.Unmarshal([]byte(`3`), c)  // nil receiver
// after
c := new(codes.Code)
json.Unmarshal([]byte(`3`), c)
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the *codes.Code is non-nil before unmarshalling.
func decodeCode(data []byte, c *codes.Code) error {
    if c == nil { return errors.New("nil *codes.Code receiver") }
    return json.Unmarshal(data, c)
}

Type guard

func isCodePtr(c *codes.Code) bool { return c != nil }

Prevention

When it happens

Trigger: Unmarshalling JSON into a nil pointer of type *codes.Code, e.g. var c *codes.Code; json.Unmarshal(data, c), or a struct field of type *codes.Code left nil while decoding a non-null value.

Common situations: Decoding a status object or status proto JSON where the code field is a *codes.Code that was never allocated; reflect-based decoders that pass a nil pointer.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/2e01c0b6f43f6375. Report an issue: GitHub.