Skip to content

AnalysisOptionsMigration excludes web/** unconditionally, silently dropping Dart web package sources from analysis #191131

Closed

Description

@AndrewDongminYoo

Steps to reproduce

AnalysisOptionsMigration (added in #187940, shipped in 3.47.0) writes a fixed seven-entry exclusion list. It is a const with no relationship to what the project actually contains (analysis_options_migration.dart#L39-L47), so web/** is written into every project — including ones where web/ is a source directory rather than a platform scaffold.

web/ is where the official dart create -t web template puts main.dart. One flutter pub get takes it out of analysis:

$ dart create -t web webrepro && cd webrepro
$ ls -1
analysis_options.yaml
CHANGELOG.md
pubspec.lock
pubspec.yaml
README.md
web

$ printf 'int probe() => "nope";\n' >> web/main.dart
$ dart analyze
  error - web/main.dart:10:16 - A value of type 'String' can't be returned from the function 'probe' because it has a return type of 'int'. - return_of_invalid_type
1 issue found.

$ flutter pub get
Resolving dependencies...
Downloading packages...
Got dependencies!
Upgrading analysis_options.yaml to exclude build and platform directories.

$ dart analyze
Analyzing webrepro...
No issues found!

The package has no android/, ios/, macos/, linux/ or windows/ directory at all. The only one of the seven names it does have is web/, which holds its code — and that is the one the migration takes out of analysis. The output names no paths, so the loss of coverage is silent, and the error stays hidden until someone reads the rewritten analysis_options.yaml.

flutter pub get in a Dart-only package is not contrived: it is what happens in mixed Flutter/Dart monorepos and Dart workspaces, where the Flutter app and the pure-Dart packages sit side by side. The same layout is described in this comment on #191056.

The same unconditional list in a Flutter app

The mechanism is visible without any web package — a project created for two platforms gets exclusions for the four it does not have, and cannot keep them out:

$ flutter create --platforms=android,ios repro_ao
$ ls -1 repro_ao
analysis_options.yaml
android
ios
lib
pubspec.lock
pubspec.yaml
README.md
repro_ao.iml
test

$ sed -n '/^analyzer:/,/^$/p' repro_ao/analysis_options.yaml
analyzer:
  exclude:
    - build/**
    - android/**
    - ios/**
    - web/**
    - windows/**
    - macos/**
    - linux/**

$ # reduce the exclude list to `- build/**`, then:
$ flutter analyze
Upgrading analysis_options.yaml to exclude build and platform directories.
Analyzing repro_ao...
No issues found! (ran in 3.4s)

$ sed -n '/^analyzer:/,/^$/p' repro_ao/analysis_options.yaml   # all seven are back

ProjectMigrator has no opt-out, and the migration runs from ensureReadyForPlatformSpecificTooling, so flutter pub get, flutter analyze, flutter run and flutter build all restore the entries. The flutter create templates emit the same fixed list (templates/app/analysis_options.yaml.tmpl).

This is adjacent to #191056 (fixed by #191082), which stopped the list from being re-applied when it is already inherited through include:. That fix does not change any of the above — excludesToExclude on master is still the same unconditional list.

Expected results

Exclusions are written only for directories the project actually uses as platform scaffolds. A Dart web package keeps web/ analyzed; a project created with --platforms=android,ios gets build/**, android/** and ios/**.

Actual results

All seven entries are written unconditionally, by both the flutter create templates and the migration, and the migration restores them on every command that reaches ensureReadyForPlatformSpecificTooling.

Suggested fix

For the platform scaffolds, FlutterProject already exposes per-platform existence through FlutterProjectPlatform.existsSync() ("Whether the platform exists in the project"), used elsewhere as project.android.existsSync() / project.linux.existsSync() (project_validator.dart:63-67, flutter_plugins.dart:1199):

final excludesToExclude = <String>[
  'build/**',
  if (project.android.existsSync()) 'android/**',
  if (project.ios.existsSync()) 'ios/**',
  if (project.windows.existsSync()) 'windows/**',
  if (project.macos.existsSync()) 'macos/**',
  if (project.linux.existsSync()) 'linux/**',
];

That alone does not cover the web/ case: WebProject.existsSync() is web/ plus web/index.html (project.dart:1186-1188), and a dart create -t web package satisfies both. The discriminator there is that it is not a Flutter project at all — its pubspec.yaml has no flutter key, so project.manifest.dependencies does not contain flutter. Skipping the migration entirely in that case seems the cleaner guard, and it would also stop the tool from editing a checked-in config file in packages that never asked for Flutter tooling.

If neither gating is wanted, an opt-out would at least make the current behaviour livable — today the only way to keep the entries out of a checked-in analysis_options.yaml is to not run any Flutter command.

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.47.0, on macOS 26.5.2 25F84 darwin-arm64, locale en-KR)
[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
[✓] Xcode - develop for iOS and macOS (Xcode 26.6)
[✓] Chrome - develop for the web
[✓] Connected device (5 available)
[✓] Network resources

• No issues found!

Activity

  1. added
    c: regressionIt was better in the past than it is now
    toolAffects the "flutter" command-line tool. See also t: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    team-toolOwned by Flutter Tool team
    on Aug 15, 2026
  2. mbcorona commented on Aug 15, 2026

    @mbcorona
    Member

    Thanks for the report. Confirmed from the source, routing to the tool team for further investigation.

  3. added a commit that references this issue on Aug 18, 2026
    d564667
  4. added a commit that references this issue on Aug 19, 2026
    c7a822e
  5. github-actions commented on Sep 2, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  6. locked as resolved and limited conversation to collaborators on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: regressionIt was better in the past than it is nowfound in release: 3.47Found to occur in 3.47has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-toolOwned by Flutter Tool teamtoolAffects the "flutter" command-line tool. See also t: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions