Skip to content

avoid_nested_futures

v0.8.0 Warning Async Safety

This rule flags a type annotation that nests one future inside another — Future<Future<T>> or FutureOr<Future<T>>.

Dart flattens futures in the two places people rely on: an async function declared to return Future<T> produces Future<T> even when its body returns a future, and Future.value infers a flattened type.

Flattening does not rewrite an explicitly written nested annotation, and await unwraps exactly one level:

Future<Future<String>> declared() async => fetchName();
final a = await declared(); // a is a Future<String>, not a String
final b = await (await declared()); // 'nick' — two awaits needed

So the annotation produces a value that behaves unlike every neighbouring future: a caller who awaits it once, as they would anything else, silently holds a Future<String> where a String was expected. Declaring the inner type directly removes the trap and makes the signature honest.

See also: Dart: asynchronous programming

Future<Future<String>> loadName() async {
return fetchName();
}
Future<String> loadName() async {
return fetchName();
}

Only explicit type annotations are checked — return types, parameter types, field and variable types. An inferred type is never reported, since Dart’s own flattening means it can never actually be a nested future.

Future<List<Future<T>>> is not flagged: a list of futures is a legitimate shape, and only the directly nested case is an error.

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:
avoid_nested_futures: false

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