Skip to content

feat: Add centralized ErrorService for consistent error handling#723

Open
TenFinges wants to merge 3 commits intoAOSSIE-Org:devfrom
TenFinges:feature/centralized-error-handling
Open

feat: Add centralized ErrorService for consistent error handling#723
TenFinges wants to merge 3 commits intoAOSSIE-Org:devfrom
TenFinges:feature/centralized-error-handling

Conversation

@TenFinges
Copy link

Description

Added a centralized ErrorService to handle errors consistently across the app. This replaces scattered error handling with a unified approach that provides user-friendly messages, accessibility support, and centralized logging.

Key changes:

  • New ErrorService class with handle() and handleSilently() methods
  • New ErrorType enum for categorizing errors (network, auth, storage, database, validation, general)
  • Added 13 new localization strings for error messages
  • Updated AuthenticationController, RoomsController, and CreateRoomController as pilot implementations

Fixes #722

Type of change

  • New feature (non-breaking change which adds functionality)
  • Refactor (does not change functionality, e.g. code style improvements, linting)

How Has This Been Tested?

  • Added 14 unit tests for ErrorService covering:
    • User-friendly message generation for all error types
    • Appwrite-specific error handling (invalid credentials, user not found, etc.)
    • Silent error handling
flutter test test/services/error_service_test.dart
# 00:02 +14: All tests passed!

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have checked my code and corrected any misspellings

Maintainer Checklist

@TenFinges TenFinges requested a review from M4dhav as a code owner January 15, 2026 15:18
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@github-actions
Copy link
Contributor

🎉 Welcome @TenFinges!
Thank you for your pull request! Our team will review it soon. 🔍

  • Please ensure your PR follows the contribution guidelines. ✅
  • All automated tests should pass before merging. 🔄
  • If this PR fixes an issue, link it in the description. 🔗

We appreciate your contribution! 🚀

@TenFinges
Copy link
Author

Please note that I've added the new error strings in English only. Previous contributors (or any native speakers) could contribute translations for Bengali, Hindi, Gujarati, Kannada, Marathi, and Punjabi.

@M4dhav M4dhav added the enhancement New feature or request label Jan 24, 2026
@M4dhav M4dhav linked an issue Jan 24, 2026 that may be closed by this pull request
Copy link
Contributor

@M4dhav M4dhav left a comment

Choose a reason for hiding this comment

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

Please fix merge conflicts

@TenFinges TenFinges force-pushed the feature/centralized-error-handling branch from 776ff7f to c6e2639 Compare January 24, 2026 18:17
@TenFinges TenFinges force-pushed the feature/centralized-error-handling branch from c6e2639 to 78904fc Compare January 24, 2026 18:19
@TenFinges TenFinges requested a review from M4dhav January 24, 2026 18:26
Comment on lines +125 to +153
/// Categorizes an error into an [ErrorType] based on its type and message.
static ErrorType _categorizeError(dynamic error) {
if (error is AppwriteException) {
return _categorizeAppwriteError(error);
}

final errorString = error.toString().toLowerCase();

if (errorString.contains('network') ||
errorString.contains('socket') ||
errorString.contains('connection') ||
errorString.contains('timeout')) {
return ErrorType.network;
}

if (errorString.contains('auth') ||
errorString.contains('credential') ||
errorString.contains('password') ||
errorString.contains('login')) {
return ErrorType.authentication;
}

if (errorString.contains('storage') ||
errorString.contains('file') ||
errorString.contains('upload')) {
return ErrorType.storage;
}

return ErrorType.general;
Copy link
Contributor

Choose a reason for hiding this comment

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

While this does seem logical enough, could you please share examples of In App Errors and how they would be segregated?

Copy link
Author

Choose a reason for hiding this comment

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

Here are a few examples of how errors are categorized:

  • Network (ErrorType.network): When a user's device loses connectivity while joining a room (rooms_controller.dart:joinRoom), the Appwrite SDK throws a SocketException: Connection refused — matches socket and connection. When a LiveKit WebSocket connection drops during pair chat (livekit_controller.dart), we get a TimeoutException — matches timeout.
  • Authentication (ErrorType.authentication): When Google/GitHub OAuth fails in authentication_controller.dart:loginWithGoogle(), the error message typically contains auth — categorized as authentication. Also happens when a session expires mid-use and account.get() fails with an auth error.
  • Storage (ErrorType.storage): When a profile image upload fails in edit_profile_controller.dart:saveProfile() via storage.createFile(), any non-Appwrite error containing file or upload in its message (e.g., FileSystemException).
  • General (ErrorType.general): Fallback for things like a FormatException when parsing room data in rooms_controller.dart (doesn't match any keyword), or a RangeError / unexpected runtime exception.

I removed ErrorType.database and ErrorType.validation from _categorizeError. In our app, database and validation errors originate strictly from Appwrite (document_not_found, general_argument_invalid, etc.) and are properly handled by _categorizeAppwriteError via structured type/code fields. Non-Appwrite Dart exceptions don't produce database or validation errors in our current codebase, so they correctly fall through to ErrorType.general.

Comment on lines +157 to +179
static ErrorType _categorizeAppwriteError(AppwriteException error) {
final type = error.type ?? '';
final code = error.code ?? 0;

// Authentication errors
if (type.contains('user_') ||
type.contains('session_') ||
code == 401 ||
code == 403) {
return ErrorType.authentication;
}

// Database/document errors
if (type.contains('document_') || type.contains('database_')) {
return ErrorType.database;
}

// Storage errors
if (type.contains('storage_') || type.contains('file_')) {
return ErrorType.storage;
}

// Validation errors
Copy link
Contributor

Choose a reason for hiding this comment

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

Same for this, please share examples of specific errors and how they would be segregated here

Copy link
Author

Choose a reason for hiding this comment

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

  • Authentication (ErrorType.authentication):

    • Login with wrong password (authentication_controller.dart:login): type: 'user_invalid_credentials', code: 401 — matches type.contains('user_').
    • Expired session when fetching rooms or profile: type: 'user_session_not_found', code: 401 — matches type.contains('session_') and code == 401.
    • Unauthorized access to another user's data: code: 403 — matches code == 403.
  • Database (ErrorType.database):

    • Fetching a deleted room in rooms_controller.dart:getRoomById(): type: 'document_not_found', code: 404 — matches type.contains('document_').
    • Deleting an already-ended pair chat in pair_chat_controller.dart:endChat() (already handled explicitly there for document_not_found): matches type.contains('document_').
    • Database query fails when loading user list: type: 'database_not_found' — matches type.contains('database_').
  • Storage (ErrorType.storage):

    • Profile image upload fails in edit_profile_controller.dart:saveProfile() via storage.createFile(): type: 'storage_file_type_unsupported' — matches type.contains('storage_').
    • Deleting a nonexistent profile image via storage.deleteFile(): type: 'file_not_found' — matches type.contains('file_').
  • Validation (ErrorType.validation):

    • Short password during login/signup (authentication_controller.dart): type: 'general_argument_invalid', code: 400 — matches both the type check and code == 400.
    • Invalid email format during change_email_controller.dart:changeEmailInAuth(): same type.
  • Network (ErrorType.network):

    • Device is offline: Appwrite SDK returns code: 0 — matches code == 0.
    • Appwrite server down: code: 503 or code: 504 — matches those code checks.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add centralized error handling service

2 participants