dispose-provider-resources

Path
lint/correctness/dispose-provider-resources
Default
On (recommended)
Origin
Falcon
Domain
riverpod
Rule
224 of 512
recommendedriverpod

Flags provider-created resources without autoDispose or ref.onDispose cleanup.

Resources created in a long-lived Riverpod provider need an explicit lifetime. Use an autoDispose provider or register the resource's cleanup with ref.onDispose. Checks package-confirmed Provider, FutureProvider and StreamProvider callbacks for resolved constructor-created instances with a zero-required-argument close or cancel method. Dispose types are left to dispose-provided-instances. Borrowed values, deferred closures and unknown types are excluded. This lifetime policy is separate from disposing arbitrary provided instances: autoDispose alone does not invoke an object's dispose. SDK sinks, sockets and subscriptions are left to the shipped leak rules unless returned as provider state. Simple source-visible factories returning borrowed values are excluded, while allocating factories remain eligible.

Invalid

example.dartdart
import 'package:riverpod/riverpod.dart';

class Channel { Channel(); Channel.named(); void close() {} }
class Subscription { Subscription(); void cancel() {} }
class Service { Service(); void dispose() {} }
class Child extends Channel {}
final channel = Provider((ref) {
  final resource = Channel();
  return resource;
});
final subscription = Provider((ref) {
  final resource = Subscription();
  return resource;
});
final named = Provider((ref) {
  final resource = Channel.named();
  return resource;
});
final explicitNew = Provider((ref) {
  final resource = new Channel();
  return resource;
});
final inherited = Provider((ref) {
  final resource = Child();
  return resource;
});
final emptyCleanup = Provider((ref) {
  final resource = Channel();
  ref.onDispose(() {});
  return resource;
});
final wrongCleanup = Provider((ref) {
  final first = Channel();
  final second = Channel();
  ref.onDispose(second.close);
  return first;
});
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
7final channel = Provider((ref) {
8 final resource = Channel();
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
11final subscription = Provider((ref) {
12 final resource = Subscription();
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
15final named = Provider((ref) {
16 final resource = Channel.named();
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
19final explicitNew = Provider((ref) {
20 final resource = new Channel();
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
23final inherited = Provider((ref) {
24 final resource = Child();
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
27final emptyCleanup = Provider((ref) {
28 final resource = Channel();
Give this provider-created resource a lifecycle: use `autoDispose` or register its cleanup with `ref.onDispose`.
32final wrongCleanup = Provider((ref) {
33 final first = Channel();

Valid

example.dartdart
import 'package:riverpod/riverpod.dart';

class Channel { Channel(); void close() {} }
class Subscription { Subscription(); void cancel() {} }
class Service { Service(); void dispose() {} }
class Value { Value(); }
final shared = Channel();
final automatic = Provider.autoDispose((ref) => Channel());
final automaticSubscription = Provider.autoDispose((ref) => Subscription());
final registered = Provider((ref) {
  final resource = Channel();
  ref.onDispose(resource.close);
  return resource;
});
final blockCleanup = Provider((ref) {
  final resource = Subscription();
  ref.onDispose(() { resource.cancel(); });
  return resource;
});
final disposed = Provider((ref) {
  final resource = Service();
  ref.onDispose(() => resource.dispose());
  return resource;
});
final borrowed = Provider((ref) => shared);
final value = Provider((ref) => Value());
final deferred = Provider((ref) => () => Channel());
Channel outsideProvider() => Channel();
void ordinaryCallback(Object Function(Ref) callback) {}
void unrelatedApi() { ordinaryCallback((ref) => Channel()); }

Configure dispose-provider-resources

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "dispose-provider-resources": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/correctness/dispose-provider-resources: <reason>