fix(api): return [] not null for empty leaderboard and account points - #412
Closed
Ryanmello07 wants to merge 1 commit into
Closed
fix(api): return [] not null for empty leaderboard and account points#412Ryanmello07 wants to merge 1 commit into
Ryanmello07 wants to merge 1 commit into
Conversation
A nil slice marshals as JSON `null`. The gomobile sdk binds these fields
as pointers, so `null` becomes a nil object that the android client
dereferences inside a jni callback -- the NPE cannot cross jni and ART
aborts the whole process. Opening the Leaderboard tab hard-crashes the
app on any deployment whose leaderboard query returns zero rows: a new
or custom server, or one before its first payout cycle.
GetLeaderboard's `earners` was a named return that was only ever appended
to, so zero rows left it nil. Two further instances of the same class,
both reproduced live against beta:
/stats/leaderboard -> {"earners":null}
/account/points -> {"account_points":null,"network_points":null}
FetchAccountPoints has the identical shape and feeds `network_points`
plus its `account_points` alias. And GetLeaderboard's controller left
Earners nil on the *error* path, so a transient query error crashed the
app just as an empty leaderboard did.
Audited every model and controller function with a named slice return: of
six with this shape, only these two are API-facing.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtgqtCmKJRXdsQ5ktiqwkg
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A nil slice marshals as JSON
null. The gomobile sdk binds these fields as pointers, sonullbecomes a nil object that the Android client dereferences inside a JNI callback — the NPE cannot cross JNI and ART aborts the whole process:Confirmed on device: opening the Leaderboard tab hard-crashes the app. This hits any deployment whose leaderboard query returns zero rows — a new or custom server, or one before its first payout cycle.
Reproduced live before the fix, and verified after:
Three instances
model.GetLeaderboard—earnersis a named return that is only ever appended to, so zero rows leaves it nil.controller.GetLeaderboarderror path — returns a result with onlyErrorset, leavingEarnersnil, so a transient query error crashes the app exactly as an empty leaderboard does.model.FetchAccountPoints— identical shape, feeding bothnetwork_pointsand its dual-emittedaccount_pointsalias, so/account/pointsreturned two null fields.Not affected
GetNetworkLeaderboardRankingreturns aNetworkRankingvalue, not a pointer, so a network with no payouts already serialises as an object. A nil*NetworkRankingon the client is the binding reflecting the JSON and resolves with the above.Audit of the whole class
Every function in
model/andcontroller/with a named slice return that is only appended to: six matches, of which only the two above are API-facing.listClientReliabilityPartitionsandMaintainClientReliabilityPartitionsare internal maintenance,GetProxyIdsSincehas no controller caller, andGetCircleUCUsersfeeds internal processing.Tests
DB-backed, calling the real functions against an empty database and asserting on the marshalled bytes rather than on non-nilness —
[]versusnullis the property that actually reaches the client. Teeth-checked: removing either initialisation fails them with "returned a nil slice; it marshals as null and crashes the client".Note:
TestAccountPointsin the controller package fails, but fails identically on the parent commit (same panic ataccount_point_controller_test.go:16) — pre-existing and unrelated to this change.