skip to content

Why can flutter analyze fail a CI job on info-level diagnostics that dart analyze lets pass, and how do you control it?

level: middleimportance: nice to knowfreq 26%

answer

  1. exit code is the verdict
  2. --fatal-infos default differs
  3. warnings fatal in both
  4. --no-fatal-infos to relax
  5. --watch for continuous analysis

basics

~10 s

flutter analyze treats info-level diagnostics as fatal by default, while dart analyze only fails on warnings and errors unless --fatal-infos is passed. Pass --no-fatal-infos to flutter analyze, or fix or reconfigure the infos.

solid answer

~30 s

Both commands run the same Dart analyzer with the project's `analysis_options.yaml`; the difference is the exit code policy. `flutter analyze` has `--fatal-infos` and `--fatal-warnings` both **on by default**, so a single info-level lint makes it exit non-zero and fails CI. `dart analyze` has `--fatal-warnings` on but `--fatal-infos` off unless you pass it. To relax the Flutter command, pass `--no-fatal-infos`; to make them match, pass `--fatal-infos` to `dart analyze`. The better long-term fix is deciding in `analysis_options.yaml` which diagnostics matter. `flutter analyze --watch` keeps analysing as files change.

code

bash · 5 lines
bash
flutter analyze                    # infos and warnings are fatal by default
flutter analyze --no-fatal-infos   # fail only on warnings and errors
dart analyze                       # warnings fatal, infos not
dart analyze --fatal-infos         # match flutter analyze's default
flutter analyze --watch            # re-analyse on every change

go deeper

for a junior

Know that flutter analyze runs static analysis and that its non-zero exit fails CI.

for a middle

Explain the severity levels and why flutter analyze and dart analyze disagree: --fatal-infos is on by default only in the Flutter command.

for a senior

Choose flags or analysis_options.yaml changes deliberately, and keep local and CI analysis identical so the verdict matches.

for a principal

Set the team's lint strictness policy, balancing consistent style against unrelated changes blocked when an SDK adds new lints.

## Same analyzer, different verdict A Flutter project can be analysed two ways: - `flutter analyze` — the Flutter tool's command; - `dart analyze` — the Dart CLI's command. Both run the **same Dart analyzer**, read the same `analysis_options.yaml` and report the same diagnostics, each with a **severity**: error, warning or info. Lints usually surface as infos. What differs is how the **exit code** is computed, and in CI the exit code is the verdict. ## The defaults | Flag | `flutter analyze` default | `dart analyze` default | |---|---|---| | `--fatal-warnings` | on | on | | `--fatal-infos` | **on** | off | | Errors | always fatal | always fatal | So with one `prefer_const_constructors` info in the code: - `flutter analyze` prints it and exits non-zero, failing the job; - `dart analyze` prints it and exits zero. Teams moving a pipeline from one command to the other are often surprised by exactly this. ## Controlling it 1. **Relax the Flutter command**: `flutter analyze --no-fatal-infos` fails only on warnings and errors. 2. **Tighten the Dart command**: `dart analyze --fatal-infos` fails on infos too, matching `flutter analyze`. 3. **Decide per diagnostic** in `analysis_options.yaml`: disable a lint you do not want, or raise one you care about to warning or error. That keeps the policy in the repository instead of in CI flags. 4. **Fix the infos**. Many are mechanical, and a clean analysis keeps real warnings visible. The choice is a team policy: strict infos keep style consistent but can block unrelated changes when a new SDK adds a lint; relaxed infos keep CI green but let them accumulate. ## Other flutter analyze options - **`--watch`** — continuous analysis that re-reports as files change. - **`--current-package`** (default on) — analyse the current project. - **`--write <file>`** — also write the diagnostics to a file. - **`--suggestions`** — show suggestions about the current Flutter project. ## Where it fits in a pipeline - Run it early; it is cheap compared with builds and tests. - Pin the SDK version in CI, because a new SDK can bring new lints in its recommended set and change the result with no code change. - Keep local and CI invocations identical, including the fatal flags, so a developer sees the CI verdict before pushing. Which lints to enable and how `include:` of a lint package works belongs to analyzer configuration; the point here is the Flutter tool's default exit policy. ## Reading the output Each diagnostic line shows the **severity**, the message, the file with line and column, and the **diagnostic code** in brackets, such as a lint name. That code is what you search for, disable in `analysis_options.yaml`, or silence locally with an `// ignore:` comment when a single case is a deliberate exception. The summary at the end counts the issues found. Two habits keep the output useful: - **Treat a growing info count as debt.** If infos are relaxed in CI, track the count so it does not grow unnoticed. - **Prefer a rule change to a flag change.** A flag in one CI script is invisible to a developer running the command locally; a line in `analysis_options.yaml` applies everywhere the project is analysed, including the IDE. ## A quick decision table | Goal | Choice | |---|---| | Strict style, every lint blocks merges | keep `flutter analyze` defaults | | Block only real problems | `--no-fatal-infos`, or raise selected lints to warning | | Same result from both commands | `dart analyze --fatal-infos` or `flutter analyze --no-fatal-infos` everywhere |

  • A team moved CI from dart analyze to flutter analyze and it went red with no code change. Why?
    The diagnostics did not change; the exit policy did. `flutter analyze` defaults `--fatal-infos` to on, so existing info-level lints that `dart analyze` tolerated now fail the job. Either fix them, pass `--no-fatal-infos`, or adjust the lints in `analysis_options.yaml`.
  • Why can an SDK upgrade turn flutter analyze red without code changes?
    Recommended lint sets and the analyzer evolve with the SDK. A new lint, or a new version of a lint package, can report infos on existing code, and with infos fatal by default the command fails. Pinning the SDK in CI makes such changes deliberate.

saying these in an interview costs you the question

  • Believes flutter analyze uses a different analyzer from dart analyze
  • Thinks infos never affect the exit code of flutter analyze
  • Assumes dart analyze fails on infos by default
  • Disables all lints to get CI green
  • Expects flutter analyze to skip analysis_options.yaml