grpc/grpc-go · error

nil receiver passed to UnmarshalJSON

Error message

nil receiver passed to UnmarshalJSON

What it means

Returned by codes.Code.UnmarshalJSON when the receiver pointer itself is nil. The Code type implements json.Unmarshaler, so calling UnmarshalJSON on a nil *Code (instead of a *Code pointing to a valid Code value) has no valid destination to write the parsed code into. This is an internal/misuse error rather than a data error.

Solutions

  1. Ensure the Code receiver is non-nil before calling UnmarshalJSON: allocate a Code value and pass its address (e.g. var c Code; c.UnmarshalJSON(b)).
  2. Prefer json.Unmarshal over calling UnmarshalJSON directly so Go manages receiver allocation.
  3. If unmarshaling into a pointer-to-pointer, initialize the inner pointer before decoding.

Example fix

// before
var c *codes.Code
c.UnmarshalJSON([]byte(`"OK"`)) // nil receiver error

// after
var c codes.Code
(&c).UnmarshalJSON([]byte(`"OK"`))
Defensive patterns

Strategy: validation

Validate before calling

// Before calling UnmarshalJSON, ensure the receiver is non-nil.
func safeUnmarshalCode(b []byte) (codes.Code, error) {
    var c codes.Code
    err := c.UnmarshalJSON(b) // c is addressable, receiver is &c
    return c, err
}

Type guard

// Prefer json.Unmarshal which allocates the target; only guard if calling manually.
func isCodeReceiverValid(c *codes.Code) bool {
    return c != nil
}

Prevention

When it happens

Trigger: Calling (*Code)(nil).UnmarshalJSON(b) directly, or json.Unmarshal into a **Code where the inner pointer is nil, or using reflection to invoke UnmarshalJSON on a nil Code pointer. The check at codes.go:232 guards against a nil receiver dereference panic.

Common situations: Custom JSON decoding wrappers that pass a nil *Code, or incorrect use of reflection-based serializers. In normal json.Unmarshal usage Go allocates the target so this is not hit; it surfaces in custom frameworks or test code that manually calls the method.

Related errors


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

Appendix: 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 0c51461d27)