{"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/0c51461d27177d997e14c642fe18c11668fc09a3/codes/codes.go#L215-L251","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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)).","Prefer json.Unmarshal over calling UnmarshalJSON directly so Go manages receiver allocation.","If unmarshaling into a pointer-to-pointer, initialize the inner pointer before decoding."],"exampleFix":"// before\nvar c *codes.Code\nc.UnmarshalJSON([]byte(`\"OK\"`)) // nil receiver error\n\n// after\nvar c codes.Code\n(&c).UnmarshalJSON([]byte(`\"OK\"`))","handlingStrategy":"validation","validationCode":"// Before calling UnmarshalJSON, ensure the receiver is non-nil.\nfunc safeUnmarshalCode(b []byte) (codes.Code, error) {\n    var c codes.Code\n    err := c.UnmarshalJSON(b) // c is addressable, receiver is &c\n    return c, err\n}","typeGuard":"// Prefer json.Unmarshal which allocates the target; only guard if calling manually.\nfunc isCodeReceiverValid(c *codes.Code) bool {\n    return c != nil\n}","tryCatchPattern":null,"preventionTips":["Never call (*Code)(nil).UnmarshalJSON directly; use json.Unmarshal into a *codes.Code.","When writing custom JSON adapters, always allocate the target value before invoking UnmarshalJSON.","Add a nil-receiver unit test to catch regressions in wrapper code."],"tags":["golang","json","grpc-codes","api-misuse","nil-pointer"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}