{"record":{"id":"2e01c0b6f43f6375","repo":"grpc/grpc-go","slug":"nil-receiver-passed-to-unmarshaljson","errorCode":null,"errorMessage":"nil receiver passed to UnmarshalJSON","messagePattern":"nil receiver passed to UnmarshalJSON","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"codes/codes.go","lineNumber":233,"sourceCode":"\t`\"ABORTED\"`:             Aborted,\n\t`\"OUT_OF_RANGE\"`:        OutOfRange,\n\t`\"UNIMPLEMENTED\"`:       Unimplemented,\n\t`\"INTERNAL\"`:            Internal,\n\t`\"UNAVAILABLE\"`:         Unavailable,\n\t`\"DATA_LOSS\"`:           DataLoss,\n\t`\"UNAUTHENTICATED\"`:     Unauthenticated,\n}\n\n// UnmarshalJSON unmarshals b into the Code.\nfunc (c *Code) UnmarshalJSON(b []byte) error {\n\t// From json.Unmarshaler: By convention, to approximate the behavior of\n\t// Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte(\"null\")) as\n\t// a no-op.\n\tif string(b) == \"null\" {\n\t\treturn nil\n\t}\n\tif c == nil {\n\t\treturn fmt.Errorf(\"nil receiver passed to UnmarshalJSON\")\n\t}\n\n\tif ci, err := strconv.ParseUint(string(b), 10, 32); err == nil {\n\t\tif ci >= _maxCode {\n\t\t\treturn fmt.Errorf(\"invalid code: %d\", ci)\n\t\t}\n\n\t\t*c = Code(ci)\n\t\treturn nil\n\t}\n\n\tif jc, ok := strToCode[string(b)]; ok {\n\t\t*c = jc\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"invalid code: %q\", string(b))\n}\n","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/codes/codes.go#L215-L251","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Allocate the receiver before unmarshalling: c := new(codes.Code); json.Unmarshal(data, c).","Unmarshal into a non-pointer codes.Code value or a wrapper struct with an allocated field.","Use json.NewDecoder and ensure the target is addressable and non-nil."],"exampleFix":"// before\nvar c *codes.Code\njson.Unmarshal([]byte(`3`), c)  // nil receiver\n// after\nc := new(codes.Code)\njson.Unmarshal([]byte(`3`), c)","handlingStrategy":"validation","validationCode":"// Ensure the *codes.Code is non-nil before unmarshalling.\nfunc decodeCode(data []byte, c *codes.Code) error {\n    if c == nil { return errors.New(\"nil *codes.Code receiver\") }\n    return json.Unmarshal(data, c)\n}","typeGuard":"func isCodePtr(c *codes.Code) bool { return c != nil }","tryCatchPattern":null,"preventionTips":["Always allocate the target before json.Unmarshal into a pointer.","Prefer non-pointer codes.Code fields in structs you decode into.","In reflect-based decoders, check nil before invoking UnmarshalJSON."],"tags":["go","grpc","codes","json","serialization"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}