-
-
Notifications
You must be signed in to change notification settings - Fork 45
CCCT-1889 - Review Personal ID Error Codes #3430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CCCT-1889 - Review Personal ID Error Codes #3430
Conversation
Added case for when error_code is actually error from a JSON response body.
Converted if-else statements to a switch statement.
Added case for INVALID_TOKEN error.
Formatted code.
Added case for INCORRECT_OTP error.
Added case for NO_RECOVERY_PIN_SET error.
Added case for FAILED_TO_UPLOAD error.
Added case for FILE_TOO_LARGE error.
Added case for MISSING_DATA error.
Added case for PHONE_MISMATCH error.
Added case for MISSING_TOKEN error.
Added case for FAILED_VALIDATING_TOKEN error.
Added case for NAME_REQUIRED error.
Added case for PHONE_NOT_VALIDATED error.
Added case for UNSUPPORTED_COUNTRY error.
Added case for ACTIVE_USER_EXISTS error.
Added case for NOT_ALLOWED error.
📝 WalkthroughWalkthroughThis pull request enhances error handling and response parsing across the API layer, particularly for Personal ID Connect operations. Changes include: improved JSON error parsing with fallback handling for an "error" field when "error_code" is empty; addition of eight new error codes to the PersonalIdOrConnectApiErrorCodes enum; expanded error case handling in PersonalIdApiHandler with a switch statement replacing conditionals; and refactored API call wrappers to use consistent multi-line formatting with appropriate parser instances passed to callbacks. Minor formatting and import reorganization adjustments are also included. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (1)
118-121: Consider a specific error code for FILE_TOO_LARGE.Currently
FILE_TOO_LARGEis mapped toSERVER_ERROR, which prevents the UI from displaying a specific "file too large" message to users. The PR description mentions a "UI consideration" for this case.If user-facing clarity is desired, consider adding
FILE_TOO_LARGE_ERRORto the enum and handling it specifically:case "FAILED_TO_UPLOAD", "FILE_TOO_LARGE": - // These error codes relate to uploading user profile photos. - onFailure(PersonalIdOrConnectApiErrorCodes.SERVER_ERROR, null); + // FILE_TOO_LARGE could have a more specific error code for better UI messaging + onFailure( + "FILE_TOO_LARGE".equals(errorCode) + ? PersonalIdOrConnectApiErrorCodes.FILE_TOO_LARGE_ERROR + : PersonalIdOrConnectApiErrorCodes.SERVER_ERROR, + null + ); return true;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
app/src/org/commcare/connect/network/NetworkUtils.kt(1 hunks)app/src/org/commcare/connect/network/base/BaseApiHandler.kt(1 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java(5 hunks)
🧰 Additional context used
🧠 Learnings (16)
📓 Common learnings
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 2912
File: app/src/org/commcare/fragments/connectId/ConnectIdPasswordVerificationFragment.java:206-213
Timestamp: 2025-01-21T18:20:43.883Z
Learning: In the Connect ID feature, server responses containing user data should be parsed using ConnectUserResponseParser to ensure consistent handling of payment information (owner_name and phone_number) and secondary phone verification across all authentication flows.
📚 Learning: 2025-06-13T15:53:12.951Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3108
File: app/src/org/commcare/connect/network/PersonalIdApiHandler.java:51-56
Timestamp: 2025-06-13T15:53:12.951Z
Learning: For `PersonalIdApiHandler`, the team’s convention is to propagate `JSONException` as an unchecked `RuntimeException` so the app crashes, signalling a contract/implementation bug rather than attempting a graceful retry.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-05-08T11:08:18.530Z
Learnt from: shubham1g5
Repo: dimagi/commcare-android PR: 0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-02-04T21:22:56.537Z
Learnt from: pm-dimagi
Repo: dimagi/commcare-android PR: 2949
File: app/src/org/commcare/fragments/connectId/ConnectIdPinFragment.java:244-275
Timestamp: 2025-02-04T21:22:56.537Z
Learning: Direct JSONObject parsing is acceptable for handling user data responses in ConnectIdPinFragment, as decided by the team. No need to enforce ConnectUserResponseParser usage in this context.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-01-21T18:20:43.883Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 2912
File: app/src/org/commcare/fragments/connectId/ConnectIdPasswordVerificationFragment.java:206-213
Timestamp: 2025-01-21T18:20:43.883Z
Learning: In the Connect ID feature, server responses containing user data should be parsed using ConnectUserResponseParser to ensure consistent handling of payment information (owner_name and phone_number) and secondary phone verification across all authentication flows.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-05-22T14:26:41.341Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3121
File: app/src/org/commcare/fragments/SelectInstallModeFragment.java:201-205
Timestamp: 2025-05-22T14:26:41.341Z
Learning: In SelectInstallModeFragment.java, the showConnectErrorMessage method intentionally omits null checks because it's called at a specific point in the startup flow where UI is guaranteed to be loaded. It's designed to crash if activity or view is null to make potential issues immediately visible rather than hiding them with defensive programming.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-04-21T18:48:08.330Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3037
File: app/src/org/commcare/connect/ConnectConstants.java:11-15
Timestamp: 2025-04-21T18:48:08.330Z
Learning: Request codes used for startActivityForResult should be unique throughout the application, even if they're used in different activities. COMMCARE_SETUP_CONNECT_LAUNCH_REQUEST_CODE and STANDARD_HOME_CONNECT_LAUNCH_REQUEST_CODE should have different values.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-05-22T14:28:35.959Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3121
File: app/src/org/commcare/activities/CommCareSetupActivity.java:360-364
Timestamp: 2025-05-22T14:28:35.959Z
Learning: In CommCareSetupActivity.java, the call to installFragment.showConnectErrorMessage() after fragment transactions is intentionally unguarded with null checks. This follows the app's design pattern where critical error paths prefer immediate crashes over silent failures, making potential issues immediately visible during development rather than hiding them with defensive programming.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-07-29T14:10:55.131Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/fragments/connect/ConnectUnlockFragment.java:0-0
Timestamp: 2025-07-29T14:10:55.131Z
Learning: In ConnectUnlockFragment.java, opportunityId values are expected to always contain valid integer strings. Integer.parseInt() should be allowed to throw NumberFormatException if invalid data is encountered, following the fail-fast philosophy used throughout the Connect feature for data contract violations.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-06-06T19:54:26.428Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3108
File: app/src/org/commcare/fragments/connect/ConnectDownloadingFragment.java:74-78
Timestamp: 2025-06-06T19:54:26.428Z
Learning: In ConnectDownloadingFragment.java and similar Connect-related code, the team prefers to let "should never happen" scenarios like null app records crash rather than add defensive null checks, following a fail-fast philosophy to catch programming errors during development.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-07-29T14:14:07.954Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/adapters/ConnectMessageAdapter.java:0-0
Timestamp: 2025-07-29T14:14:07.954Z
Learning: In the CommCare Android Connect messaging system (ConnectMessageAdapter.java), the team prefers to let getMessage() potentially return null and crash rather than adding defensive null checks. This follows the fail-fast philosophy used throughout the Connect feature to catch programming errors immediately during development.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-07-29T14:10:58.243Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/fragments/connect/ConnectJobsListsFragment.java:0-0
Timestamp: 2025-07-29T14:10:58.243Z
Learning: In ConnectJobsListsFragment.java, the team intentionally uses different error handling strategies: JSONException should throw RuntimeException to crash the app (fail-fast for data contract violations), while IOException should be logged and allow graceful continuation (for network/stream issues). This follows the established Connect module pattern of treating different exception types differently based on their nature.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.javaapp/src/org/commcare/connect/network/NetworkUtils.kt
📚 Learning: 2025-07-29T14:11:36.386Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/fragments/connect/ConnectJobsListsFragment.java:0-0
Timestamp: 2025-07-29T14:11:36.386Z
Learning: In ConnectJobsListsFragment.java error handling for JSON parsing, if the JSONObject obj is null when passed to handleCorruptJob(), the team prefers to let the code crash rather than adding defensive null checks. This follows the fail-fast philosophy used throughout the Connect feature to catch programming errors immediately rather than masking them.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-07-29T14:08:55.466Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3248
File: app/src/org/commcare/fragments/connect/ConnectUnlockFragment.java:0-0
Timestamp: 2025-07-29T14:08:55.466Z
Learning: In ConnectUnlockFragment.java and similar Connect-related code, the team has agreed that JSONExceptions should crash the app by throwing RuntimeException (fail-fast approach for data contract violations), while IOExceptions should be logged and allow processing to continue (graceful handling for network/stream issues). This intentional inconsistency in error handling reflects different treatment for different types of failures.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.javaapp/src/org/commcare/connect/network/NetworkUtils.kt
📚 Learning: 2025-01-28T09:38:59.882Z
Learnt from: pm-dimagi
Repo: dimagi/commcare-android PR: 2847
File: app/src/org/commcare/connect/network/connectId/ApiService.java:8-63
Timestamp: 2025-01-28T09:38:59.882Z
Learning: The ConnectID API service methods should use Map<String, String> for request bodies and ResponseBody for responses, as per team preference.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
📚 Learning: 2025-04-18T20:13:29.655Z
Learnt from: OrangeAndGreen
Repo: dimagi/commcare-android PR: 3040
File: app/src/org/commcare/android/database/connect/models/ConnectJobDeliveryFlagRecord.java:39-55
Timestamp: 2025-04-18T20:13:29.655Z
Learning: In the CommCare Android Connect feature, the JSON object passed to `ConnectJobDeliveryFlagRecord.fromJson()` method should never be null based on the implementation design.
Applied to files:
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
🧬 Code graph analysis (1)
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (4)
app/src/org/commcare/connect/network/connectId/parser/ReportIntegrityResponseParser.java (1)
ReportIntegrityResponseParser(19-28)app/src/org/commcare/connect/network/NetworkUtils.kt (1)
getErrorCodes(32-49)app/src/org/commcare/connect/network/base/BaseApiHandler.kt (2)
createCallback(62-87)processSuccess(68-85)app/src/org/commcare/connect/network/ApiPersonalId.java (1)
ApiPersonalId(52-483)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Lint Code Base
🔇 Additional comments (6)
app/src/org/commcare/connect/network/NetworkUtils.kt (1)
38-46: LGTM! Good defensive handling of server inconsistency.The fallback to check the "error" field when "error_code" is empty properly addresses the server-side inconsistency mentioned in the PR description.
app/src/org/commcare/connect/network/base/BaseApiHandler.kt (1)
40-55: LGTM! Enum additions support expanded error handling.The new error codes are well-named, follow existing conventions, and align with the error handling cases added in
PersonalIdApiHandler.java.app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (4)
49-82: LGTM! Exception handling follows framework patterns.The try-catch blocks properly distinguish between JSON parsing errors (data contract issues) and I/O errors (network issues), routing both to appropriate error codes via
onFailure. This aligns with the error handling pattern established inBaseApiHandler.createCallback.
84-169: LGTM! Comprehensive error handling with appropriate fallback.The switch statement thoroughly covers the error codes identified in the PR description. The default case correctly returns
falseto allow the base handler to process unrecognized error codes, and the exception handling around the switch provides good defensive coverage.
172-326: LGTM! Consistent callback pattern with appropriate parser selection.The refactored API call methods now consistently use either the local
createCallback(for flows requiringPersonalIdSessionDataand custom error handling) orBaseApiHandler.createCallback(for simpler flows). The multi-line formatting improves readability, and parser selection is appropriate for each endpoint.
103-108: Verify crash behavior and error handling consistency.The review comment's concern cannot be fully resolved because
BaseApiHandleris an external dependency not available in the codebase. However, examination reveals two important issues requiring verification:
Crash behavior uncertain: All observable
onFailure()implementations (in fragments and services) show graceful error handling rather than crashes. Without theBaseApiHandlerimplementation, the actual behavior when callingonFailure()with aThrowablecannot be confirmed.Inconsistency with team conventions: Per learnings, the team's convention is to propagate
JSONExceptionas an uncheckedRuntimeExceptionto crash (fail-fast for data contract violations), whileIOExceptionshould be logged gracefully. However, lines 63–69 catch both exception types and pass them toonFailure(), contradicting this convention.Please manually verify that the error handling approach matches the intended crash/logging behavior and aligns with established team patterns.
Removed try-catch block that was preventing the app from crashing for certain error codes.
Ran Ktlint.
|
@conroy-ricketts +1 for the ticket description and your observations |
shubham1g5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the great notes here!
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
Outdated
Show resolved
Hide resolved
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
Outdated
Show resolved
Hide resolved
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
Show resolved
Hide resolved
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
Show resolved
Hide resolved
…nto task/CCCT-1889-review-personal-id-error-codes
Added more comments.
Removed throwable from INVALID_TOKEN case.
Reverted changes to NetworkUtils.kt to ensure consistency and alignment of handling error code from server.
Defined specific error routing for INCORRECT_OTP.
|
Right now, PersonalIdApiHandler has error handling but I was thinking of having this kind of parsing (error_code) in |
@Jignesh-dimagi I'm open to the idea! My thinking was that it may be better to do the error handling in |
Ran Ktlint on BaseApiHandler.kt.
Tweaked code to crash the app on FILE_TOO_LARGE error.
…nto task/CCCT-1889-review-personal-id-error-codes
shubham1g5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, think it would be nice to confirm in PR safety story that we have tested any core functional changes in the PR (like - incorrect otp check) before we merge this in.
|
@damagatchi retest this please |
CCCT-1889
Technical Summary
I reviewed how we are handling all the possible Personal ID error codes coming form server. Please see my notes for each one below:
INVALID_TOKENis being sent with the label"error", and here it is being sent with the label"error_code". This is just one example of the inconsistency. I added some changes to our code to account for that, but I wonder if this was an error on the server side?error_codeinstead of justerrorto get more consistency on the server side and let mobile decide how to handle different error codes instead of telling mobile what to do. In general,errormight contain a string sentence like "Something went wrong" whereaserror_codewould be just a code like"INVALID_TOKEN"for example.handleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler)./users/recover/confirm_pin/users/recover/initiate_deactivation/users/recover/confirm_deactivationPersonalIdOrConnectApiErrorCodes.FAILED_AUTH_ERROR), but we did not formally specify the error code from server, so I added some code to directly use thePersonalIdOrConnectApiErrorCodes.FAILED_AUTH_ERRORwhen the error code is"INCORRECT_OTP". The behavior should remain the same.PersonalIdOrConnectApiErrorCodes.INCORRECT_OTP_ERRORto a user-visible message that says "You have entered the wrong 6-digit passcode. Please try again."/users/recover/initiate_deactivation/users/recover/confirm_deactivation/users/recover/confirm_deactivationhandleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler)./users/recover/confirm_pin/users/recover/confirm_pin/users/set_recovery_pin500server error which we are already handling viaPersonalIdOrConnectApiErrorCodes.SERVER_ERROR. But, we did not formally specify the error code from server, so I added some code to directly use thePersonalIdOrConnectApiErrorCodes.SERVER_ERRORwhen the error code is"FAILED_TO_UPLOAD". The behavior should remain the same.500server error which we are already handling viaPersonalIdOrConnectApiErrorCodes.SERVER_ERROR. But, we did not formally specify the error code from server, so I added some code to directly use thePersonalIdOrConnectApiErrorCodes.SERVER_ERRORwhen the error code is"FILE_TOO_LARGE". The behavior should remain the same.handleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler).handleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler).handleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler).handleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler).handleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler).PersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERROR), but we did not formally specify the error code from server, so I added some code to directly use thePersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERRORwhen the error code is"PHONE_NOT_VALIDATED". The behavior should remain the same.PersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERROR), but we did not formally specify the error code from server, so I added some code to directly use thePersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERRORwhen the error code is"UNSUPPORTED_COUNTRY". The behavior should remain the same./users/generate_manual_otp/users/add_credentialhandleErrorCodeIfPresent()function inPersonalIdApiHandler) to a new Runtime Exception (via thehandle()function inPersonalIdApiErrorHandler).PersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERROR), but we did not formally specify the error code from server, so I added some code to directly use thePersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERRORwhen the error code is"NOT_ALLOWED". The behavior should remain the same.Safety Assurance
Safety story
I tested some error codes by going through the Personal ID signup flow and triggering the errors while watching the device logs, and I tested others by forcing errors in the code.
I also made sure that a successful Personal ID signup still works/behaves as expected.
Edit: I verified that the app will crash when we see the appropriate error codes (i.e. the app will crash for the following error codes:
NO_RECOVERY_PIN_SET,FILE_TOO_LARGE,MISSING_DATA,PHONE_MISMATCH,MISSING_TOKEN,FAILED_VALIDATING_TOKEN,NAME_REQUIRED,ACTIVE_USER_EXISTS). This is expected - if a crash occurs then it needs to be brought to our attention. I also verified that if server sends theINCORRECT_OTPcode, then mobile will display a message that says "You have entered the wrong 6-digit passcode. Please try again."QA Plan
It would be good for QA to go through the Personal ID signup flow and ensure that nothing unexpected happens, especially if an error occurs.