跪拜 Guibai
← All articles
Flutter · Android · Frontend

Flutter 3.47's Auto-Migration Silently Corrupts Analysis Configs

By 恋猫de小郭 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Any Flutter developer who runs `flutter pub get` on 3.47 risks having their `analysis_options.yaml` silently mutated. Teams using shared lint packages via `include:` will see duplicate exclusions injected on every command, and pure Dart web projects lose analyzer coverage of their `web/` source tree until they upgrade past the patched version.

Summary

Flutter 3.47 shipped an `AnalysisOptionsMigration` that runs during everyday commands like `flutter pub get` and `flutter analyze`. Its job is to add default platform-directory exclusions to `analysis_options.yaml`, but the initial implementation ignored the `include:` directive entirely, causing it to repeatedly append duplicate exclusions to monorepo configs that already inherited them from a shared package.

The second flaw was a hardcoded list of seven directories to exclude — `build/`, `android/`, `ios/`, `web/`, `windows/`, `macos/`, `linux/` — regardless of which platforms a project actually uses. For pure Dart web projects created with `dart create -t web`, this meant the genuine source directory `web/` was silently excluded from analysis.

Emergency patches landed within days. The fix now recursively resolves `include:` chains and canonical paths to avoid infinite loops, checks whether a package actually depends on Flutter before touching its config, and dynamically generates the exclusion list based on the platform directories that physically exist in the project.

Takeaways
Flutter 3.47's `AnalysisOptionsMigration` fires on `flutter pub get`, `flutter analyze`, `flutter run`, and `flutter build` — not just during an explicit upgrade step.
The migration did not parse `include:` in `analysis_options.yaml`, so projects inheriting exclusions from a shared package were treated as unconfigured and had duplicate exclusions appended.
A hardcoded list of seven platform directories was excluded for every project, even if those platforms were never added to the project.
Pure Dart web projects created with `dart create -t web` had their `web/` source directory excluded from analysis because the migration treated `web/` as a Flutter platform shell.
Fix PR #191082 added recursive `include:` resolution with canonical-path tracking to prevent infinite loops between mutually including configs.
Fix PR #191151 gates the migration on whether the package actually depends on Flutter and dynamically builds the exclusion list from directories that exist on disk.
The `flutter create` template was also patched so new projects don't inherit the same hardcoded list.
Conclusions

A migration that mutates user source files should never run as a side effect of everyday commands; it belongs behind an explicit upgrade or doctor command.

The root cause is a review process that treated a destructive file mutation as a trivial template update, skipping the edge cases that `include:` and non-Flutter Dart projects represent.

Hardcoding platform knowledge into the tool rather than reading it from the project's actual filesystem state is a recurring source of Flutter tooling regressions.

Concepts & terms
AnalysisOptionsMigration
A Flutter 3.47 mechanism that automatically adds default `analyzer.exclude` entries to a project's `analysis_options.yaml`. It runs as part of `ensureReadyForPlatformSpecificTooling()`, which is invoked by common commands like `flutter pub get`.
analysis_options.yaml `include:` directive
A Dart analysis configuration feature that lets one `analysis_options.yaml` file inherit settings from another file or package via a URI. The Analyzer resolves the chain at analysis time, but Flutter 3.47's initial migration only inspected the local file literally.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗