Skip to content

fix: prevent LateInitializationError crashes in AuthServiceImpl#1048

Open
vibhutomer wants to merge 1 commit into
mosip:masterfrom
vibhutomer:fix/auth-service-late-init-crash
Open

fix: prevent LateInitializationError crashes in AuthServiceImpl#1048
vibhutomer wants to merge 1 commit into
mosip:masterfrom
vibhutomer:fix/auth-service-late-init-crash

Conversation

@vibhutomer
Copy link
Copy Markdown

@vibhutomer vibhutomer commented May 11, 2026

Description

This PR resolves a widespread architectural bug that caused "silent crashes" across multiple core services, including AuthServiceImpl and MachineKeyImpl.

Previously, strict non-nullable interface constraints forced developers to use the late keyword for variables assigned inside try-catch blocks. In the event of a PlatformException or network failure, the catch block would execute, but the methods would still attempt to return the uninitialized late variable, resulting in an immediate LateInitializationError and a fatal application crash.

Changes Made

  • Refactored SPI Interfaces: Updated auth_service.dart and machine_key_service.dart to allow nullable return types (e.g., Future<User?>, Future<Machine?>) where appropriate.
  • Complex Object Safety: Removed the late keyword from validateUser, login, packetAuthentication, and getMachineKeys. These methods now safely return null if the underlying API call fails, allowing the UI to handle the error gracefully.
  • String Method Safety: Refactored logout(), stopAlarmService(), forgotPasswordUrl(), getIdleTime(), getAutoLogoutPopupTimeout(), and getPasswordLength() in auth_service_impl.dart. Removed the late keyword and initialized them with safe default values ("").

Related Issue

Closes #1047

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Stability improvement (prevents fatal runtime errors and refactors interfaces)

Checklist

  • My code follows the style guidelines of this project.
  • I have performed a self-review of my own code.
  • My changes generate no new warnings or exceptions.

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling in authentication processes (user validation, login, and packet authentication) to gracefully manage platform-level failures
    • Enhanced machine key retrieval with better failure recovery mechanisms

Review Change Stack

…ects

Signed-off-by: vibhutomer <vibhutomer25@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Walkthrough

Service method return types are relaxed from non-nullable to nullable across authentication and machine key operations. Interface contracts in the platform SPI layer are updated, followed by matching implementations that now safely return null when native API calls fail or throw exceptions.

Changes

Nullable Service Return Types

Layer / File(s) Summary
Service Interface Contracts
lib/platform_spi/auth_service.dart, lib/platform_spi/machine_key_service.dart
AuthService.validateUser, login, and packetAuthentication return types change to nullable (User?, AuthResponse?, PacketAuth?). MachineKeyService.getMachineKeys return type changes to nullable (Machine?).
Authentication Service Implementation
lib/platform_android/auth_service_impl.dart
validateUser, login, and packetAuthentication methods remove late variable declarations and initialize as nullable types, returning null on PlatformException or generic exception instead of throwing LateInitializationError.
Machine Key Service Implementation
lib/platform_android/machine_key_service_impl.dart
getMachineKeys removes late variable declaration, initializes machine as null, and returns null on API call failure instead of throwing LateInitializationError.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Late variables cause crashes, it's true,
So nullable types came into view,
When APIs fail and exceptions arise,
We gracefully return null—no surprise!
The services now handle the storm,
Keeping the app safe and warm. 🌧️→☀️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: preventing LateInitializationError crashes by removing late keyword usage in AuthServiceImpl methods.
Linked Issues check ✅ Passed The pull request addresses the core objectives from issue #1047: removing late keyword usage and making return types nullable in AuthServiceImpl and MachineKeyImpl.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing LateInitializationError by relaxing return types to nullable and removing late variables. No unrelated modifications present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
lib/platform_android/auth_service_impl.dart (6)

64-76: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: late keyword still present—LateInitializationError risk remains.

The logout() method still uses late String logoutResponse; on line 66. If either catch block is executed, logoutResponse remains uninitialized, and returning it will throw a LateInitializationError—the exact bug this PR aims to fix. According to the PR objectives, this method should initialize with a safe default (empty string).

🐛 Proposed fix: Initialize with empty string
   Future<String> logout() async {
-    late String logoutResponse;
+    String logoutResponse = "";
     try {
       logoutResponse = await AuthResponseApi().logout();
-    }on PlatformException {
+    } on PlatformException {
       debugPrint('Logout Api call failed!');
-    }catch (e) {
+    } catch (e) {
       debugPrint(e.toString());
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 64 - 76, The
logout() method declares a late String logoutResponse and returns it even when
an exception occurs; initialize logoutResponse to a safe default (e.g., empty
string) at declaration so it is always defined, keep the try/catch using
AuthResponseApi().logout() as-is, and ensure any error paths still return the
initialized value from logout().

117-128: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: late keyword still present—LateInitializationError risk remains.

The getAutoLogoutPopupTimeout() method still uses late String refreshLoginTime; on line 119. If either catch block is executed, the variable remains uninitialized, causing a LateInitializationError when returned.

🐛 Proposed fix: Initialize with empty string
   Future<String> getAutoLogoutPopupTimeout() async {
-    late String refreshLoginTime;
+    String refreshLoginTime = "";
     try {
       refreshLoginTime = await AuthResponseApi().getAutoLogoutPopupTimeout();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 117 - 128, The
getAutoLogoutPopupTimeout method uses a late String refreshLoginTime which may
remain uninitialized if an exception is thrown; initialize refreshLoginTime with
a safe default (e.g., empty string or a sensible fallback) when declaring it, or
return the fallback directly from the catch blocks so refreshLoginTime is never
returned uninitialized; locate getAutoLogoutPopupTimeout and the
refreshLoginTime variable and update the declaration/exception handling
accordingly.

104-115: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: late keyword still present—LateInitializationError risk remains.

The getIdleTime() method still uses late String idleTime; on line 106. If either catch block is executed, the variable remains uninitialized, causing a LateInitializationError when returned.

🐛 Proposed fix: Initialize with empty string
   Future<String> getIdleTime() async {
-    late String idleTime;
+    String idleTime = "";
     try {
       idleTime = await AuthResponseApi().getIdleTime();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 104 - 115, The
getIdleTime method uses a late String (idleTime) which can remain uninitialized
if an exception occurs; replace the late variable with a safely initialized
default (e.g., empty string) or return a default directly in the catch blocks so
getIdleTime() never returns an uninitialized value—update the
AuthResponseApi().getIdleTime() call handling in getIdleTime to assign a default
on exceptions and ensure the method always returns a valid String.

78-89: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: late keyword still present—LateInitializationError risk remains.

The stopAlarmService() method still uses late String stopAlarmServiceResponse; on line 80. If either catch block is executed, the variable remains uninitialized, causing a LateInitializationError when returned—the exact issue this PR is meant to resolve.

🐛 Proposed fix: Initialize with empty string
   Future<String> stopAlarmService() async{
-    late String stopAlarmServiceResponse;
+    String stopAlarmServiceResponse = "";
     try {
       stopAlarmServiceResponse = await AuthResponseApi().stopAlarmService();
-    }on PlatformException {
+    } on PlatformException {
       debugPrint('stopAlarmService Api call failed!');
-    }catch (e) {
+    } catch (e) {
       debugPrint(e.toString());
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 78 - 89, The method
stopAlarmService currently declares late String stopAlarmServiceResponse which
can remain uninitialized if an exception occurs; replace the late declaration by
initializing the variable (e.g., String stopAlarmServiceResponse = '' ) or make
it nullable (String? stopAlarmServiceResponse) and return a safe default so the
return never throws; update references in stopAlarmService and keep the await
call to AuthResponseApi().stopAlarmService() and the existing catch blocks
intact.

91-102: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: late keyword still present—LateInitializationError risk remains.

The forgotPasswordUrl() method still uses late String forgotPasswordResponse; on line 93. If either catch block is executed, the variable remains uninitialized, causing a LateInitializationError when returned.

🐛 Proposed fix: Initialize with empty string
   Future<String> forgotPasswordUrl() async{
-    late String forgotPasswordResponse;
+    String forgotPasswordResponse = "";
     try {
       forgotPasswordResponse = await AuthResponseApi().forgotPasswordUrl();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 91 - 102,
forgotPasswordUrl() declares late String forgotPasswordResponse which can remain
uninitialized if a catch runs; initialize the variable (e.g., String
forgotPasswordResponse = ''; ) or return a safe default from the catch blocks
instead so you never return an uninitialized value. Update the forgotPasswordUrl
method to set a default response before the try or to return a default in the
PlatformException / catch blocks when calling
AuthResponseApi().forgotPasswordUrl().

143-154: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: late keyword still present—LateInitializationError risk remains.

The getPasswordLength() method still uses late String passwordLength; on line 145. If either catch block is executed, the variable remains uninitialized, causing a LateInitializationError when returned.

🐛 Proposed fix: Initialize with empty string
   Future<String> getPasswordLength() async {
-    late String passwordLength;
+    String passwordLength = "";
     try {
       passwordLength = await AuthResponseApi().getPasswordLength();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 143 - 154,
getPasswordLength uses a `late String passwordLength` which can remain
uninitialized if an exception is caught, causing a LateInitializationError;
change this by initializing passwordLength with a safe default (e.g., `String
passwordLength = ""`) or by returning a default value directly from the catch
blocks, and ensure the call to AuthResponseApi().getPasswordLength() is awaited
into that initialized variable so getPasswordLength always returns a defined
String.
🧹 Nitpick comments (4)
lib/platform_android/auth_service_impl.dart (3)

50-51: ⚡ Quick win

Remove commented-out code.

The commented-out line showing the old late PacketAuth packetAuth; should be deleted.

🧹 Proposed cleanup
       String username, String password) async {
-    // late PacketAuth packetAuth;
     PacketAuth? packetAuth;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 50 - 51, Remove the
leftover commented-out declaration "// late PacketAuth packetAuth;" and keep
only the active nullable declaration "PacketAuth? packetAuth;" so the file no
longer contains dead/commented code; update any nearby comments if needed to
reflect that packetAuth is now nullable.

34-35: ⚡ Quick win

Remove commented-out code.

The commented-out line showing the old late AuthResponse authResponse; should be deleted.

🧹 Proposed cleanup
       String username, String password, bool isConnected) async {
-    // late AuthResponse authResponse;
     AuthResponse? authResponse;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 34 - 35, Remove the
dead commented-out declaration "// late AuthResponse authResponse;" and keep
only the active nullable declaration "AuthResponse? authResponse;" so there is
no commented legacy code; ensure no other references rely on the removed comment
and run a quick formatting pass to clean whitespace.

19-20: ⚡ Quick win

Remove commented-out code.

The commented-out line showing the old late User user; should be deleted to keep the codebase clean.

🧹 Proposed cleanup
   Future<User?> validateUser(String username, String langCode) async {
-    // late User user;
     User? user;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/auth_service_impl.dart` around lines 19 - 20, Remove the
commented-out dead code by deleting the line containing the old declaration
"late User user;" so only the active nullable declaration "User? user;" remains
in auth_service_impl.dart; this cleans up the file and avoids leaving stale
commented code next to the active User? user field.
lib/platform_android/machine_key_service_impl.dart (1)

17-17: ⚡ Quick win

Remove commented-out code.

The commented-out line should be deleted rather than left in the codebase.

🧹 Proposed cleanup
   Future<Machine?> getMachineKeys() async {
-    // late Machine machine;
     Machine? machine;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/platform_android/machine_key_service_impl.dart` at line 17, Delete the
leftover commented-out declaration "// late Machine machine;" to clean up dead
code; remove the commented line referencing Machine/machine from
machine_key_service_impl.dart so the file contains only active code and no
unused commented declarations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@lib/platform_android/auth_service_impl.dart`:
- Around line 64-76: The logout() method declares a late String logoutResponse
and returns it even when an exception occurs; initialize logoutResponse to a
safe default (e.g., empty string) at declaration so it is always defined, keep
the try/catch using AuthResponseApi().logout() as-is, and ensure any error paths
still return the initialized value from logout().
- Around line 117-128: The getAutoLogoutPopupTimeout method uses a late String
refreshLoginTime which may remain uninitialized if an exception is thrown;
initialize refreshLoginTime with a safe default (e.g., empty string or a
sensible fallback) when declaring it, or return the fallback directly from the
catch blocks so refreshLoginTime is never returned uninitialized; locate
getAutoLogoutPopupTimeout and the refreshLoginTime variable and update the
declaration/exception handling accordingly.
- Around line 104-115: The getIdleTime method uses a late String (idleTime)
which can remain uninitialized if an exception occurs; replace the late variable
with a safely initialized default (e.g., empty string) or return a default
directly in the catch blocks so getIdleTime() never returns an uninitialized
value—update the AuthResponseApi().getIdleTime() call handling in getIdleTime to
assign a default on exceptions and ensure the method always returns a valid
String.
- Around line 78-89: The method stopAlarmService currently declares late String
stopAlarmServiceResponse which can remain uninitialized if an exception occurs;
replace the late declaration by initializing the variable (e.g., String
stopAlarmServiceResponse = '' ) or make it nullable (String?
stopAlarmServiceResponse) and return a safe default so the return never throws;
update references in stopAlarmService and keep the await call to
AuthResponseApi().stopAlarmService() and the existing catch blocks intact.
- Around line 91-102: forgotPasswordUrl() declares late String
forgotPasswordResponse which can remain uninitialized if a catch runs;
initialize the variable (e.g., String forgotPasswordResponse = ''; ) or return a
safe default from the catch blocks instead so you never return an uninitialized
value. Update the forgotPasswordUrl method to set a default response before the
try or to return a default in the PlatformException / catch blocks when calling
AuthResponseApi().forgotPasswordUrl().
- Around line 143-154: getPasswordLength uses a `late String passwordLength`
which can remain uninitialized if an exception is caught, causing a
LateInitializationError; change this by initializing passwordLength with a safe
default (e.g., `String passwordLength = ""`) or by returning a default value
directly from the catch blocks, and ensure the call to
AuthResponseApi().getPasswordLength() is awaited into that initialized variable
so getPasswordLength always returns a defined String.

---

Nitpick comments:
In `@lib/platform_android/auth_service_impl.dart`:
- Around line 50-51: Remove the leftover commented-out declaration "// late
PacketAuth packetAuth;" and keep only the active nullable declaration
"PacketAuth? packetAuth;" so the file no longer contains dead/commented code;
update any nearby comments if needed to reflect that packetAuth is now nullable.
- Around line 34-35: Remove the dead commented-out declaration "// late
AuthResponse authResponse;" and keep only the active nullable declaration
"AuthResponse? authResponse;" so there is no commented legacy code; ensure no
other references rely on the removed comment and run a quick formatting pass to
clean whitespace.
- Around line 19-20: Remove the commented-out dead code by deleting the line
containing the old declaration "late User user;" so only the active nullable
declaration "User? user;" remains in auth_service_impl.dart; this cleans up the
file and avoids leaving stale commented code next to the active User? user
field.

In `@lib/platform_android/machine_key_service_impl.dart`:
- Line 17: Delete the leftover commented-out declaration "// late Machine
machine;" to clean up dead code; remove the commented line referencing
Machine/machine from machine_key_service_impl.dart so the file contains only
active code and no unused commented declarations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 248b5019-d175-4df1-ae06-61c3d2f2f018

📥 Commits

Reviewing files that changed from the base of the PR and between aef4fb6 and 6681502.

📒 Files selected for processing (4)
  • lib/platform_android/auth_service_impl.dart
  • lib/platform_android/machine_key_service_impl.dart
  • lib/platform_spi/auth_service.dart
  • lib/platform_spi/machine_key_service.dart

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Application crash due to LateInitializationError in service implementations

1 participant