Fixes#200 — sync log repeatedly filled with MissingPluginException(No implementation found for method read on channel plugins.it.nomads.com/flutter_secure_storage).
Root cause:_isPermanentError in both _AccountSync and _JmapAccountSync did not recognise MissingPluginException as a permanent failure. When flutter_secure_storage's platform channel is unavailable (seen on certain Android devices), every call to getPassword() throws this exception. The loop treated it as a transient error and kept retrying with exponential back-off, producing a continuous stream of failures in the sync log.
Fix:
Add if (e is MissingPluginException) return true; to _isPermanentError in both sync loop classes (IMAP and JMAP) so the loop stops immediately instead of retrying.
Import package:flutter/services.dart show MissingPluginException for the type check.
Test plan
Added regression test MissingPluginException from secure storage stops IMAP sync loop permanently in test/unit/account_sync_manager_test.dart
Test was written first and confirmed failing before the fix (2 sync log entries after kick)
Test passes after the fix (loop stops permanently after 1 failure)
## Summary
Fixes #200 — sync log repeatedly filled with `MissingPluginException(No implementation found for method read on channel plugins.it.nomads.com/flutter_secure_storage)`.
**Root cause:** `_isPermanentError` in both `_AccountSync` and `_JmapAccountSync` did not recognise `MissingPluginException` as a permanent failure. When `flutter_secure_storage`'s platform channel is unavailable (seen on certain Android devices), every call to `getPassword()` throws this exception. The loop treated it as a transient error and kept retrying with exponential back-off, producing a continuous stream of failures in the sync log.
**Fix:**
- Add `if (e is MissingPluginException) return true;` to `_isPermanentError` in both sync loop classes (IMAP and JMAP) so the loop stops immediately instead of retrying.
- Import `package:flutter/services.dart show MissingPluginException` for the type check.
## Test plan
- [x] Added regression test `MissingPluginException from secure storage stops IMAP sync loop permanently` in `test/unit/account_sync_manager_test.dart`
- Test was written first and confirmed **failing** before the fix (2 sync log entries after kick)
- Test passes after the fix (loop stops permanently after 1 failure)
- [x] All 446 unit + widget tests pass
- [x] `flutter analyze` — no issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Fixes #200 — sync log repeatedly filled with
MissingPluginException(No implementation found for method read on channel plugins.it.nomads.com/flutter_secure_storage).Root cause:
_isPermanentErrorin both_AccountSyncand_JmapAccountSyncdid not recogniseMissingPluginExceptionas a permanent failure. Whenflutter_secure_storage's platform channel is unavailable (seen on certain Android devices), every call togetPassword()throws this exception. The loop treated it as a transient error and kept retrying with exponential back-off, producing a continuous stream of failures in the sync log.Fix:
if (e is MissingPluginException) return true;to_isPermanentErrorin both sync loop classes (IMAP and JMAP) so the loop stops immediately instead of retrying.package:flutter/services.dart show MissingPluginExceptionfor the type check.Test plan
MissingPluginException from secure storage stops IMAP sync loop permanentlyintest/unit/account_sync_manager_test.dartflutter analyze— no issues🤖 Generated with Claude Code