{"record":{"id":"107601f8f6f0ea09","repo":"hyperledger/fabric","slug":"must-be-pointers-to-struct-but-got-pointer-to-v","errorCode":null,"errorMessage":"must be pointers to struct, but got pointer to %v","messagePattern":"must be pointers to struct, but got pointer to (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/lifecycle/serializer.go","lineNumber":85,"sourceCode":"// to the same value again) custom serialization is required.\ntype Serializer struct {\n\t// Marshaler, when nil uses the standard protobuf impl.\n\t// Can be overridden for test.\n\tMarshaler Marshaler\n}\n\n// SerializableChecks performs some boilerplate checks to make sure the given structure\n// is serializable.  It returns the reflected version of the value and a slice of all\n// field names, or an error.\nfunc (s *Serializer) SerializableChecks(structure any) (reflect.Value, []string, error) {\n\tvalue := reflect.ValueOf(structure)\n\tif value.Kind() != reflect.Pointer {\n\t\treturn reflect.Value{}, nil, errors.Errorf(\"must be pointer to struct, but got non-pointer %v\", value.Kind())\n\t}\n\n\tvalue = value.Elem()\n\tif value.Kind() != reflect.Struct {\n\t\treturn reflect.Value{}, nil, errors.Errorf(\"must be pointers to struct, but got pointer to %v\", value.Kind())\n\t}\n\n\tallFields := make([]string, value.NumField())\n\tfor i := 0; i < value.NumField(); i++ {\n\t\tfieldName := value.Type().Field(i).Name\n\t\tfieldValue := value.Field(i)\n\t\tallFields[i] = fieldName\n\t\tswitch fieldValue.Kind() {\n\t\tcase reflect.String:\n\t\tcase reflect.Int64:\n\t\tcase reflect.Slice:\n\t\t\tif fieldValue.Type().Elem().Kind() != reflect.Uint8 {\n\t\t\t\treturn reflect.Value{}, nil, errors.Errorf(\"unsupported slice type %v for field %s\", fieldValue.Type().Elem().Kind(), fieldName)\n\t\t\t}\n\t\tcase reflect.Pointer:\n\t\t\tif !fieldValue.Type().Implements(ProtoMessageType) {\n\t\t\t\treturn reflect.Value{}, nil, errors.Errorf(\"unsupported pointer type %v for field %s (must be proto)\", fieldValue.Type().Elem(), fieldName)\n\t\t\t}","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/lifecycle/serializer.go#L67-L103","documentation":"After confirming the argument is a pointer, SerializableChecks dereferences it and requires the pointee to be a struct, since field-by-field serialization only works on structs. A pointer to a non-struct (int, string, slice, etc.) triggers this error with the dereferenced kind.","triggerScenarios":"Calling Serialize/Deserialize/IsSerialized with *int, *string, *[]byte or any pointer-to-non-struct type.","commonSituations":"Trying to serialize scalar or slice values directly through the lifecycle serializer; generic helper code that wraps arbitrary types in pointers; test code checking serializer behavior.","solutions":["Define a dedicated struct type whose fields hold the data, and pass a pointer to that struct","Move scalar values into a struct field instead of serializing them directly","Use a plain state PutState call for raw key/value data rather than the struct serializer"],"exampleFix":"// before\nval := int64(42)\ns.Serialize(state, metadata, &val)\n// after\ntype Counter struct{ Value int64 }\ns.Serialize(state, metadata, &Counter{Value: 42})","handlingStrategy":"type-guard","validationCode":"rv := reflect.ValueOf(v)\nif rv.Kind() != reflect.Pointer || rv.Elem().Kind() != reflect.Struct {\n  return errors.New(\"lifecycle serializer requires pointer-to-struct\")\n}","typeGuard":"func isPointerToStruct(v any) bool {\n  rv := reflect.ValueOf(v)\n  return rv.Kind() == reflect.Pointer && rv.Elem().Kind() == reflect.Struct\n}","tryCatchPattern":"_, _, err := s.SerializableChecks(input)\nif err != nil && strings.Contains(err.Error(), \"pointers to struct\") {\n  // input is *scalar/*slice — restructure into a struct\n}","preventionTips":["Do not serialize raw scalars or slices via the struct serializer","Define dedicated metadata structs for persisted state","Use plain PutState/GetState for non-struct data"],"tags":["fabric","serialization","reflection","type-error"],"backgroundTag":"pointer-to-nonstruct-serialization","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}