loadPerAccount has a check for whether the account exists or not at the end:
Future<PerAccountStore> loadPerAccount(int accountId) async {
assert(_accounts.containsKey(accountId));
final store = await doLoadPerAccount(accountId);
if (!_accounts.containsKey(accountId)) {
// [removeAccount] was called during [doLoadPerAccount].
store.dispose();
throw AccountNotFoundException();
}
return store;
}
Hypothetically, this check can only be reached if the account is logged out while loading the PerAccountStore. However, because of a runtime error that would happen right after the inner request returns, we cannot reach the if-block here.
The error comes from a null-check at the start of PerAccountStore.fromInitialSnapshot:
final account = globalStore.getAccount(accountId)!;
[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: Null check operator used on a null value
#0 new PerAccountStore.fromInitialSnapshot (package:zulip/model/store.dart:285:54)
#1 UpdateMachine.load (package:zulip/model/store.dart:913:35)
<asynchronous suspension>
#2 LiveGlobalStore.doLoadPerAccount (package:zulip/model/store.dart:836:27)
<asynchronous suspension>
#3 GlobalStore.loadPerAccount (package:zulip/model/store.dart:155:15)
<asynchronous suspension>
#4 GlobalStore._reloadPerAccount (package:zulip/model/store.dart:135:19)
PerAccountStore.fromInitialSnapshot is called near the end of LiveGlobalStore.doLoadPerAccount with no asynchronous gap, meaning that the null-check will always fail ahead of AccountNotFoundException being raised if the user logs out during the asynchronous gap from the /api/register-queue request or globalStore.updateAccount:
This is a bug that the if (!_accounts.containsKey(accountId)) check was meant to catch. The error should be thrown earlier, ideally every time before the account is accessed, similar to the if (mounted) checks and BuildContext.
loadPerAccounthas a check for whether the account exists or not at the end:Hypothetically, this check can only be reached if the account is logged out while loading the
PerAccountStore. However, because of a runtime error that would happen right after the inner request returns, we cannot reach the if-block here.The error comes from a null-check at the start of
PerAccountStore.fromInitialSnapshot:PerAccountStore.fromInitialSnapshotis called near the end ofLiveGlobalStore.doLoadPerAccountwith no asynchronous gap, meaning that the null-check will always fail ahead ofAccountNotFoundExceptionbeing raised if the user logs out during the asynchronous gap from the /api/register-queue request orglobalStore.updateAccount:This is a bug that the
if (!_accounts.containsKey(accountId))check was meant to catch. The error should be thrown earlier, ideally every time before the account is accessed, similar to theif (mounted)checks andBuildContext.