Skip to content

async_value_nullable_pattern

v0.8.0 Warning Fix Riverpod State

Flags AsyncValue(:final value?) when the value type is nullable. The ? pattern matches only when the value is non-null, which is not the same question as whether a value has loaded.

For an AsyncValue<int?>, a successfully loaded null is a real result. The ? pattern rejects it, so that case silently falls through to the loading or error branch — the UI shows a spinner forever for data that actually arrived. hasValue: true asks the question you meant: has this loaded?

See also: Riverpod - AsyncValue

switch (asyncValue) { // AsyncValue<int?>
case AsyncValue(:final value?): // LINT — a loaded null never matches
print(value);
default:
return const CircularProgressIndicator();
}
switch (asyncValue) { // AsyncValue<int?>
case AsyncValue(:final value, hasValue: true):
print(value);
default:
return const CircularProgressIndicator();
}

The rule stays silent where the ? pattern is precise:

// Non-nullable value: null can only mean "not loaded"
void fn(AsyncValue<int> asyncValue) {
switch (asyncValue) {
case AsyncValue(:final value?):
print(value);
default:
break;
}
}
// AsyncData.hasValue is always true, so the null check carries the meaning
void onData(AsyncValue<int?> asyncValue) {
switch (asyncValue) {
case AsyncData(:final value?):
print(value);
default:
break;
}
}

This rule is in the core preset, so it is on with preset: core, preset: recommended or preset: opinionated.

To turn it off:

many_lints.yaml
rules:
async_value_nullable_pattern: false

To keep the rule on but skip certain paths, use per-rule exclude.