riverpod-ref-in-provider-lifecycle
/riverpod-ref-in-provider-lifecycle
Naprawia błąd Riverpod o użyciu Ref w cyklu życia providera, na przykład przy dispose albo w asynchronicznych wywołaniach po anulowaniu.
- Autor
- divinevideo ↗
- Repozytorium
- divine-mobile ↗
- Licencja
- AGPL-3.0
- Ostatnia zmiana repozytorium
- 27.10.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 1
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 2
Brak sygnałów. Repozytorium zmienione 27.10.2026, bez odwołań do wycofanych modeli i API.
AGPL-3.0, copyleft: przeróbki udostępniane innym muszą mieć tę samą licencję.
Co robi i kiedy
Naprawia błąd Riverpod o użyciu Ref w cyklu życia providera, na przykład przy dispose albo w asynchronicznych wywołaniach po anulowaniu.
Oryginalny opis (EN)
Fix Riverpod "Cannot use Ref or modify other providers inside life-cycles/selectors" crash in @riverpod provider bodies. Use when: (1) Crash during provider disposal with this exact error message, (2) Using keepAlive() with timer-based disposal, (3) Async callbacks (.then, .catchError) try to use ref.read() or ref.invalidateSelf(), (4) Error occurs after ref.onCancel/onResume/onDispose callbacks fire. Solution: wrap ref operations in try-catch or avoid using ref in async callbacks entirely.
Jak działa
- Problem
- Context / Trigger Conditions
- Solution
- Anti-Pattern: ref.mounted Check
- Verification
- Example
- Notes
- Related Skills
- References
Podgląd SKILL.md
---
name: riverpod-ref-in-provider-lifecycle
description: |
Fix Riverpod "Cannot use Ref or modify other providers inside life-cycles/selectors" crash
in @riverpod provider bodies. Use when: (1) Crash during provider disposal with this exact
error message, (2) Using keepAlive() with timer-based disposal, (3) Async callbacks (.then,
.catchError) try to use ref.read() or ref.invalidateSelf(), (4) Error occurs after
ref.onCancel/onResume/onDispose callbacks fire. Solution: wrap ref operations in try-catch
or avoid using ref in async callbacks entirely.
author: Claude Code
version: 1.0.0
date: 2026-02-01
---
# Riverpod ref Usage in Provider Lifecycle Callbacks
## Problem
When using `ref.keepAlive()` with timer-based auto-disposal in `@riverpod` providers,
async callbacks (`.then()`, `.catchError()`) that execute during or after disposal
will crash when they try to use `ref.read()`, `ref.invalidateSelf()`, or any other
ref operation.
## Context / Trigger Conditions
**Error message:**
```
'package:riverpod/src/core/ref.dart': Failed assertion: line 216 pos 7:
'_debugCallbackStack == 0': Cannot use Ref or modify other providers inside life-cycles/selectors.
```
**Typical scenario:**
1. Provider uses `ref.keepAlive()` with a timer in `ref.onCancel()`:
```dart
final link = ref.keepAlive();
ref.onCancel(() {
Timer(Duration(seconds: 15), () {
link.close(); // Triggers disposal
});
});
```
2. Provider has async callbacks that use `ref`:
```dart
someAsyncOperation().then((_) {
if (ref.mounted) { // THIS CHECK IS NOT ENOUGH!
ref.invalidateSelf();
}
});
```
3. Timer fires while async callback is pending
4. CRASH - `ref.mounted` returns `true` but using `ref` is still forbidden
**Key insight:** `ref.mounted` returns `true` during lifecycle callbacks, but
using `ref` operations is still forbidden. This is counter-intuitive but by design.
## Solution
### Option 1: Wrap ref operations in try-catch (Recommended)
```dart
someAsyncOperation().then((_) {
try {
ref.read(someProvider.notifier).update(/*...*/);
} catch (e) {
Log.debug('Provider likely disposed: $e');
}
});
```
### Option 2: Avoid ref operations in async callbacks entirely
Instead of:
```dart
// BAD - uses ref in async callback
openVineVideoCache.removeCorruptedVideo(videoId).then((_) {
if (ref.mounted) {
ref.invalidateSelf(); // CRASH!
}
});
```
Do:
```dart
// GOOD - fire-and-forget without ref
unawaited(
openVineVideoCache.removeCorruptedVideo(videoId).then((_) {
Log.info('Cache removed'); // No ref usage
}),
);
// Let user retry manually or provider recreates on next access
```
### Option 3: Capture provider state synchronously first
```dart
// Read state BEFORE async operation
final notifier = ref.read(someProvider.notifier);
// Use captured reference in callback (not ref)
someAsyncOperation().then((_) {
notifier.doSomething(); // Uses captured reference, not ref
});
```
## Anti-Pattern: ref.mounted Check
```dart
// THIS DOES NOT WORK!
someAsyncOperation().then((_) {
if (ref.mounted) { // Returns true during lifecycle!
ref.invalidateSelf(); // Still crashes!
}
});
```
The `ref.mounted` check is insufficient because:
1. Timer fires, `link.close()` called
2. Riverpod enters disposal lifecycle (callback stack > 0)
3. `ref.mounted` check passes (still returns `true`!)
4. `ref.invalidateSelf()` called
5. CRASH - ref operations forbidden during lifecycle callbacks
## Verification
1. Rapidly scroll through content that uses the provider
2. Navigate away and back while providers are active
3. Let the keepAlive timers fire naturally (wait 15+ seconds after scrolling)
4. Check Crashlytics/console for the lifecycle assertion error
5. Error should no longer occur
## Example
### Before (causes crash):
```dart
@riverpod
VideoPlayerController videoController(Ref ref, String videoId) {
final link = ref.keepAlive();
ref.onCancel(() {
Timer(Duration(seconds: 15), () => link.close());
});
final controller = VideoPlayerController.networkUrl(url);
controller.initialize().catchError((error) {
// CRASH! This callback may run during disposal
if (ref.mounted) {
ref.invalidateSelf(); // Assertion failure!
}
});
return controller;
}
```
### After (safe):
```dart
@riverpod
VideoPlayerController videoController(Ref ref, String videoId) {
final link = ref.keepAlive();
ref.onCancel(() {
Timer(Duration(seconds: 15), () => link.close());
});
final controller = VideoPlayerController.networkUrl(url);
controller.initialize().catchError((error) {
// Safe - wrapped in try-catch
try {
ref.read(fallbackProvider.notifier).state = newValue;
} catch (e) {
Log.debug('Provider disposed during error handling: $e');
}
// Don't invalidateSelf - let provider recreate on next access
});
return controller;
}
```
## Notes
- This issue is specific to `@riverpod` provider bodies, not widget dispose()
- The related skill `riverpod-ref-read-in-dispose` covers widget lifecycle issues
- Consider whether `ref.invalidateSelf()` is even necessary - often the provider
will be recreated naturally on next access
- For truly critical cleanup, use `ref.onDispose()` which runs synchronously
before the lifecycle callback stack check
- This bug is particularly common with video players, image loaders, and other
resources that use keepAlive() with timer-based disposal
## Related Skills
- `riverpod-ref-read-in-dispose`: For widget dispose() ref.read() issues
- `flutter-dispose-timer-test-failure`: For timer-related test failures
## References
- [Riverpod ref.keepAlive](https://riverpod.dev/docs/concepts/modifiers/auto_dispose#refkeepalive)
- [Riverpod lifecycle callbacks](https://riverpod.dev/docs/concepts/provider_lifecycles)
Wersje
W bazie nie ma innych skilli o nazwie riverpod-ref-in-provider-lifecycle.
Identyczna treść występuje jeszcze w 1 innych folderach na GitHubie. Tu pokazujemy jedną, najlepiej ocenioną kopię.
Migawka bazy z 28.10.2026 · wersja paczki baf70522ff36 (skrót SHA-256 całej paczki)
Pobrania w ostatnich 30 dniach: 0 · ranking
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 100riverpod-ref-read-in-dispose
Usuwa błąd Riverpod przy użyciu ref w dispose(): serwis zapisuje w initState, żeby wywołać go podczas sprzątania widżetu. - 100riverpod-patterns
Podpowiada wzorce Riverpod dla aplikacji Flutter: pisanie providerów, obsługę AsyncValue, użycie ref i cykl życia providerów. - 100flutter-riverpod3
Pomaga pisać i recenzować kod Riverpod 3 we Flutterze bez generowania kodu: wybór typu providera, wstrzykiwanie zależności, klasy Notifier i AsyncNotifier, ref.watch, read, listen i select oraz ponawianie. - 100riverpod-ref-listen-build-only
Naprawia asercję Riverpod 3.x, w której ref.listen wywołano poza metodą build widżetu, i sprawdza testy widżetów po poprawce. - 100state-management-riverpod
Wymusza w Riverpod 3.x jeden Notifier dla stanu funkcji, niezmienny stan i jednokierunkowy przepływ danych, z repozytorium jako jedyną ścieżką zapisu. - 100riverpod
Pomaga w Riverpod przy konfiguracji providerów, łączeniu żądań, zwalnianiu stanu, przekazywaniu argumentów, efektach ubocznych i testowaniu providerów.