Skip to content

Resolve crash that occurs when a connection to Keycloak fails#3822

Open
allan-on wants to merge 9 commits intomainfrom
bugfix/3821-fix-auth-server-connection-crash
Open

Resolve crash that occurs when a connection to Keycloak fails#3822
allan-on wants to merge 9 commits intomainfrom
bugfix/3821-fix-auth-server-connection-crash

Conversation

@allan-on
Copy link
Copy Markdown
Contributor

@allan-on allan-on commented Jan 7, 2026

IMPORTANT: Where possible all PRs must be linked to a Github issue

Fixes #3821

Engineer Checklist

  • I have written Unit tests for any new feature(s) and edge cases for bug fixes
  • I have added any strings visible on UI components to the strings.xml file
  • I have updated the CHANGELOG.md file for any notable changes to the codebase
  • I have run ./gradlew spotlessApply and ./gradlew spotlessCheck to check my code follows the project's style guide
  • I have built and run the FHIRCore app to verify my change fixes the issue and/or does not break the app
  • I have checked that this PR does NOT introduce breaking changes that require an update to Content and/or Configs? If it does add a sample here or a link to exactly what changes need to be made to the content.

Code Reviewer Checklist

  • I have verified Unit tests have been written for any new feature(s) and edge cases
  • I have verified any strings visible on UI components are in the strings.xml file
  • I have verifed the CHANGELOG.md file has any notable changes to the codebase
  • I have verified the solution has been implemented in a configurable and generic way for reuseable components
  • I have built and run the FHIRCore app to verify the change fixes the issue and/or does not break the app

Refactored fetchAccessToken to simplify and catch all exceptions generically
@allan-on allan-on added Error-Handling Bug-fix PR label for bug fix on release notes Authentication labels Jan 7, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Jan 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 24.6%. Comparing base (aaebbb6) to head (b9828fc).
⚠️ Report is 10 commits behind head on main.

❌ Your project check has failed because the head coverage (24.6%) is below the target coverage (25.0%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##              main   #3822     +/-   ##
=========================================
- Coverage     25.0%   24.6%   -0.4%     
- Complexity     844     849      +5     
=========================================
  Files          297     305      +8     
  Lines        16102   16516    +414     
  Branches      2689    2747     +58     
=========================================
+ Hits          4038    4076     +38     
- Misses       11580   11956    +376     
  Partials       484     484             
Flag Coverage Δ
engine 60.7% <100.0%> (-0.3%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...re/engine/data/remote/shared/TokenAuthenticator.kt 74.8% <100.0%> (+0.3%) ⬆️

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Result.failure(sslHandShakeException)
} catch (e: Exception) {
Result.failure(e)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Instead of omitting all these, you can retain them and add.

catch (e: Exception) {
  Result.failure(e)
}

At the end, to catch any missed exceptions.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses app crashes when Keycloak is unreachable by ensuring fetchAccessToken() returns a failed Result instead of letting uncaught connection-related exceptions propagate.

Changes:

  • Add a generic exception catch in TokenAuthenticator.fetchAccessToken() to prevent crashes on previously-unhandled failures (e.g., connection errors).
  • Update the corresponding unit test to validate failure handling across multiple exception types.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/shared/TokenAuthenticator.kt Adds a fallback catch (e: Exception) when fetching tokens to avoid crashes on unhandled exceptions.
android/engine/src/test/java/org/smartregister/fhircore/engine/auth/TokenAuthenticatorTest.kt Refactors exception-handling test to iterate over multiple exception types and assert failures consistently.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +275 to +282
// Test with various exception types to verify generic exception handling
val exceptions =
listOf(
HttpException(Response.error<OAuthResponse>(401, mockk(relaxed = true))),
UnknownHostException(),
SSLHandshakeException("SSL error"),
IOException("IO error"),
)
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The new test aims to cover “all network exceptions”, but it doesn’t include the ConnectException that triggered the reported crash (issue #3821). Add ConnectException (and ideally SocketTimeoutException) to this list so the regression is directly covered.

Copilot uses AI. Check for mistakes.
Comment on lines 166 to +173
} catch (httpException: HttpException) {
Result.failure(httpException)
} catch (unknownHostException: UnknownHostException) {
Result.failure(unknownHostException)
} catch (sslHandShakeException: SSLHandshakeException) {
Result.failure(sslHandShakeException)
} catch (e: Exception) {
Result.failure(e)
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

fetchAccessToken now catches Exception, which will also catch kotlinx.coroutines.CancellationException and prevent cooperative cancellation (and can cause structured-concurrency bugs). Consider adding a catch (e: CancellationException) { throw e } before this, and narrowing the generic catch to IOException (plus HttpException) to avoid masking programmer errors while still covering ConnectException, SocketTimeoutException, UnknownHostException, SSLHandshakeException, etc.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@allan-on Can you apply this change it is okay.

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

Labels

Authentication Bug-fix PR label for bug fix on release notes Error-Handling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The application crashes when it is unable to connect to its authentication server (Keycloak)

4 participants