fix(claude): guard ClaudeConfig.notifyListeners against use-after-dispose
setProjectDir / refresh / ensureProbe each await disk I/O then call notifyListeners(), but — unlike load(), which already guards — they didn't re-check _disposed afterward. A project switch (or watcher refresh) racing the config's disposal fires notifyListeners() on a disposed ChangeNotifier and throws "used after disposed". Surfaced deterministically by the test deflake (pumpEventQueue drains the async that Future.delayed(Duration.zero) was masking). Add the same `if (_disposed) return;` guard to all three. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -73,6 +73,12 @@ heading, and (b) bumping `pubspec.yaml` `version:` in the same commit.
|
||||
session persistence moved to `--resume` (D-77); the toolchain no longer probes
|
||||
for it or warns when it's absent, on any platform.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`ClaudeConfig` no longer crashes on a project switch that races teardown.**
|
||||
`setProjectDir` / `refresh` / `ensureProbe` now skip `notifyListeners()` if the
|
||||
config was disposed during their async load (the guard `load()` already had).
|
||||
|
||||
## [2.4.1] — 2026-06-12
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -257,6 +257,7 @@ class ClaudeConfig extends ChangeNotifier {
|
||||
if (probe == null) return; // stay on the static fallback
|
||||
_probe = probe;
|
||||
await _writeProbeCache(probe);
|
||||
if (_disposed) return; // a slow probe racing a teardown mustn't notify a disposed notifier
|
||||
notifyListeners();
|
||||
} finally {
|
||||
_probing = false;
|
||||
@@ -268,6 +269,7 @@ class ClaudeConfig extends ChangeNotifier {
|
||||
/// not re-resolved (the binary doesn't change under us at runtime).
|
||||
Future<void> refresh() async {
|
||||
await _loadDiskConfig();
|
||||
if (_disposed) return; // a watcher-driven refresh racing a teardown mustn't notify a disposed notifier
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -278,6 +280,7 @@ class ClaudeConfig extends ChangeNotifier {
|
||||
_stopWatching();
|
||||
_projectDir = dir;
|
||||
await _loadDiskConfig();
|
||||
if (_disposed) return; // a project switch racing a teardown mustn't notify a disposed notifier
|
||||
_startWatchers();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user