{"record":{"id":"ed63bc6581e614cd","repo":"openimsdk/open-im-server","slug":"user-not-found-s","errorCode":null,"errorMessage":"user not found: %s","messagePattern":"user not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/common/convert/friend.go","lineNumber":48,"sourceCode":"func FriendPb2DB(friend *sdkws.FriendInfo) *model.Friend {\n\tdbFriend := &model.Friend{}\n\terr := datautil.CopyStructFields(dbFriend, friend)\n\tif err != nil {\n\t\treturn nil\n\t}\n\tdbFriend.FriendUserID = friend.FriendUser.UserID\n\tdbFriend.CreateTime = timeutil.UnixSecondToTime(friend.CreateTime)\n\treturn dbFriend\n}\n\nfunc FriendDB2Pb(ctx context.Context, friendDB *model.Friend, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (*sdkws.FriendInfo, error) {\n\tusers, err := getUsers(ctx, []string{friendDB.FriendUserID})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tuser, ok := users[friendDB.FriendUserID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"user not found: %s\", friendDB.FriendUserID)\n\t}\n\n\treturn &sdkws.FriendInfo{\n\t\tFriendUser: user,\n\t\tCreateTime: friendDB.CreateTime.Unix(),\n\t}, nil\n}\n\nfunc FriendsDB2Pb(ctx context.Context, friendsDB []*model.Friend, getUsers func(ctx context.Context, userIDs []string) (map[string]*sdkws.UserInfo, error)) (friendsPb []*sdkws.FriendInfo, err error) {\n\tif len(friendsDB) == 0 {\n\t\treturn nil, nil\n\t}\n\tvar userID []string\n\tfor _, friendDB := range friendsDB {\n\t\tuserID = append(userID, friendDB.FriendUserID)\n\t}\n\n\tusers, err := getUsers(ctx, userID)","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/openimsdk/open-im-server/blob/175a7bb0673eca18e9d1b10bff4f728da6b1b513/pkg/common/convert/friend.go#L30-L66","documentation":"FriendDB2Pb converts a friend DB row to its protobuf representation, which requires embedding the friend's user profile. It loads the user via getUsers; if the user map lacks the FriendUserID entry, the friend row points to a user record that no longer exists, so it fails with 'user not found: %s'.","triggerScenarios":"The friends table contains a row whose FriendUserID has no corresponding row in the users table when the friend list is fetched/converted.","commonSituations":"Manual DB cleanup deleted users but not their friend links; failed/partial cascade delete of a user account; data import/migration inconsistency; replication lag in read replicas.","solutions":["Clean up orphaned friend rows: DELETE FROM friends WHERE friend_user_id NOT IN (SELECT user_id FROM users)","Restore the missing user record if it should exist (from backup)","Add cascade delete on user removal so friend rows are purged together","Make getUsers/convert tolerant: skip and log missing users instead of failing the whole list"],"exampleFix":"// before\nuser, ok := users[friendDB.FriendUserID]\nif !ok { return nil, fmt.Errorf(\"user not found: %s\", friendDB.FriendUserID) }\n// after\nuser, ok := users[friendDB.FriendUserID]\nif !ok {\n    log.ZWarn(ctx, \"friend user missing, skipping\", nil, \"userID\", friendDB.FriendUserID)\n    return nil, nil // or filter upstream\n}","handlingStrategy":"validation","validationCode":"// detect orphaned friend rows before converting\norphanSQL := `SELECT f.friend_user_id FROM friends f LEFT JOIN users u ON u.user_id = f.friend_user_id WHERE u.user_id IS NULL`\nrows, _ := db.Query(orphanSQL) // clean up or restore these users first","typeGuard":null,"tryCatchPattern":"info, err := convert.FriendDB2Pb(ctx, friendDB)\nif err != nil {\n\tif strings.HasPrefix(err.Error(), \"user not found:\") {\n\t\tlog.ZWarn(ctx, \"orphan friend row, skipping\", err)\n\t\treturn nil // skip instead of failing whole list\n\t}\n\treturn err\n}","preventionTips":["Enable cascade delete of friend rows when a user is removed","Run a periodic orphan-record reconciliation job","Avoid manual deletes from the users table without cleaning friends"],"tags":["database","data-consistency","friends"],"backgroundTag":"orphaned-database-record","analyzedSha":"175a7bb0673eca18e9d1b10bff4f728da6b1b513","analyzedAt":"2026-09-04T16:52:56.821Z","contentChangedAt":"2026-09-04T16:52:56.821Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}