Updated a package dependency last week, flutter analyze immediately lit up with a wall of deprecation warnings, and I did what you’re supposed to do — ran dart fix --dry-run expecting it to clean most of it up automatically. Got back “Nothing to fix!” Which, given the analyzer was actively showing dozens of fixable warnings on screen at that exact moment, was more than a little confusing.
Quick Answer
- “Nothing to fix!” despite visible deprecation warnings usually means
dart fixhas already processed those files in a prior run and isn’t reprocessing them, even though the package’s fix rules changed - Try
dart fix --applyon a single file first to confirm whether it’s a project-wide issue or file-specific - Creating a fresh file with the same deprecated code and running dart fix against it is a good diagnostic — if the new file gets fixed and the old one doesn’t, you’re dealing with this exact caching-like behavior
- Manually running
dart pub getagain after a dependency update doesn’t reset this state, despite feeling like it should - The most reliable workaround is fixing the affected code manually, or upgrading and immediately running dart fix in the same commit before other changes touch those files
Why It Fails
dart fix doesn’t work off dart analyze‘s live output directly — it computes its own fix proposals based on two sources: lint rules from your analysis_options.yaml, and API migration data from a fix_data.yaml file that packages can ship in their lib/ directory to describe how old API usage should be rewritten. When a package updates and adds new deprecation fixes to its fix_data.yaml, you’d reasonably expect dart fix to immediately pick those up across your whole project. In practice, this doesn’t always happen cleanly.
A few specific things cause this in practice:
- Files dart fix has already “seen” don’t get reprocessed even when fix rules change. This is the core of the confusing behavior — files that were previously analyzed by dart fix can end up skipped on later runs, even after a dependency bump introduces new fixable deprecations in that exact code. Brand new files with identical code get fixed immediately, which is what makes this so disorienting to debug — the fix logic clearly works, it’s just not being applied to files it’s seen before.
- The diagnostic isn’t actually enabled.
dart fixonly applies fixes tied to diagnostics that are active — some are implicitly enabled (compilation errors), but lints need to be explicitly turned on inanalysis_options.yaml. If the relevant lint isn’t enabled, there’s nothing for dart fix to attach a fix to, even if the underlying code pattern is genuinely outdated. - Not every diagnostic has an associated fix. The analyzer can flag something as deprecated without there being a corresponding automated rewrite rule for it — the warning and the fix are two separate things maintained separately, and a warning existing doesn’t guarantee a fix exists to go with it.
- Editor buffer vs. saved file mismatch. dart fix reads from disk, not your editor’s in-memory state — unsaved changes won’t be seen, and it’s an easy thing to forget mid-troubleshooting session.
- Package-specific fix rules not being picked up after an update. When you bump a package version specifically to get new deprecation fixes in its
fix_data.yaml, that new fix data should apply — but combined with the “already seen” behavior above, it sometimes just doesn’t for files that predate the update.
Technical Comparison
| Symptom | Cause | Fix Path |
|---|---|---|
| “Nothing to fix!” but analyzer shows warnings | Lint not enabled in analysis_options.yaml | Enable the relevant lint explicitly |
| “Nothing to fix!” on old files, but new files with identical code get fixed | Known dart fix state/caching quirk | Manual fix, or fix immediately after the dependency bump |
| dart fix works on some files but not others in the same project | Unsaved changes, or file-specific skip state | Save all files, retry on isolated file first |
| dart analyze shows deprecation, but no “Try replacing…” suggestion | No associated fix exists for that diagnostic | Manual migration required, check package changelog |
Step-by-Step Fixes
Step 1: Confirm the Lint or Diagnostic Is Actually Enabled
Check your analysis_options.yaml:
yaml
include: package:flutter_lints/flutter.yaml
linter:
rules:
# confirm the relevant rule isn't accidentally disabledIf you’re chasing a specific deprecation, make sure deprecated_member_use isn’t suppressed anywhere in your config or in // ignore: comments scattered through the affected files.
Step 2: Save Everything and Retry
dart fix --dry-runSounds almost too basic to mention, but unsaved editor buffers are invisible to this command. Save all open files first, every time, before troubleshooting further.
Step 3: Test on a Single File to Isolate the Behavior
dart fix --dry-run lib/features/your_file.dartIf this specific file reports “Nothing to fix!” while dart analyze clearly flags it, move to the diagnostic test below rather than assuming it’s a config issue.
Step 4: Diagnostic Test — New File With the Same Code
This confirms whether you’re dealing with the known “already seen” behavior:
- Create a brand-new file with the exact same deprecated code pattern
- Run
dart fix --dry-runagainst just that new file - If the new file gets a proposed fix and the original doesn’t, you’ve confirmed it — the fix logic works, it’s just not reapplying to previously-processed files
Step 5: Apply Fixes Immediately After a Dependency Bump
If you’re specifically updating a package to pick up new migration fixes, run dart fix in the same session, before touching anything else:
flutter pub upgrade some_package
dart fix --dry-run
dart fix --applyDoing this immediately, before other edits touch the same files, gives you the best chance of the new fix data actually applying cleanly.
Step 6: Manual Migration as the Fallback
When dart fix genuinely won’t touch a file no matter what, you’re down to doing it by hand. Check the package’s changelog or migration guide for the specific old-API-to-new-API mapping — most well-maintained packages document this clearly when they deprecate something, even if dart fix itself won’t apply it automatically.
What Actually Worked For Me
First thing I tried was the obvious one — assumed I’d forgotten to save a file somewhere, went through and saved everything, reran dart fix --dry-run. Same “Nothing to fix!” result. So I checked analysis_options.yaml next, on the theory that maybe the specific lint had gotten disabled somewhere along the way. Nope, everything looked correctly configured, and dart analyze was still showing the warnings clearly with “Try replacing the use of the deprecated member” attached to each one — which specifically implies a fix should exist.
That’s when I did the new-file test, mostly out of frustration more than a clear plan. Copy-pasted one deprecated line into a scratch file, ran dart fix against just that file, and it proposed the fix instantly. Same exact code, same project, same analysis_options.yaml — but the original file wouldn’t budge and the new one fixed immediately. At that point it was pretty clearly not a configuration problem on my end, just dart fix’s own state tracking not reprocessing files it had already touched in an earlier run, even though the package’s fix data had genuinely changed since then.
Ended up just fixing the affected files by hand using the package’s migration guide, which took maybe twenty minutes for what would’ve been a two-second dart fix --apply if it had worked as expected. Mildly annoying, but not exactly a crisis — your mileage may vary on how many files get caught by this, since it seems tied to whichever files dart fix happened to process in earlier runs.
Advanced Fixes and Edge Cases
Checking whether the fix is “unsafe” and excluded by default. Some fix tooling (particularly third-party linters layered on top of dart fix, like DCM) separates fixes into safe and unsafe categories, where unsafe fixes — ones that can change code behavior, not just formatting — are excluded unless you explicitly opt in with an --unsafe flag. If you’re using one of these tools alongside plain dart fix, check whether the fix you’re expecting falls into that excluded category.
Fix data mismatches between package versions. If you upgraded a package expecting new fix_data.yaml rules and dart fix still reports nothing, double check the actual installed version resolved by pub — a version constraint elsewhere in your dependency tree can sometimes hold a package back from the version that actually shipped the new fix data, separate from the “already seen” issue entirely.
Running dart fix per diagnostic code rather than project-wide. If a broad dart fix --dry-run reports nothing but you suspect a specific rule should apply, target it directly:
dart fix --dry-run --code=deprecated_member_useThis sometimes surfaces fixes that a general run doesn’t, particularly in larger projects with a lot of mixed lint rules active.
Formatting fallout after a large dart fix run. If you do get a large batch of fixes to apply successfully, run dart format immediately after — const insertions and other automated rewrites can push lines past your formatting limits, and CI formatting checks will catch that if you don’t clean it up in the same pass.
What Rarely Works
Running dart pub get or dart pub upgrade again, hoping it’ll somehow reset whatever state is causing files to be skipped, doesn’t actually do anything for this specific issue — it refreshes your dependency versions, not dart fix’s internal tracking of which files it’s already processed. Similarly, deleting and reinstalling the .dart_tool folder is a common shotgun troubleshooting step for Dart/Flutter weirdness generally, but for this particular “already seen” behavior it doesn’t reliably help either, since the behavior has been reported as tied to the fix tool’s own logic rather than cached build artifacts.
Prevention Tips
- Run
dart fix --applyright after any dependency upgrade that touches deprecated APIs, before other edits pile up on the same files - Don’t assume “Nothing to fix!” means your code is clean — cross-check against
dart analyzeoutput specifically when you know a package just added migration fixes - Keep an eye on package changelogs when upgrading, since manual migration steps are sometimes documented there even when dart fix should theoretically handle it
- If you’re maintaining a large codebase, consider running dart fix as a matter of habit on a schedule rather than only reactively, since catching new fixable warnings early reduces how much ends up needing manual migration later
FAQ
Is “Nothing to fix!” always a sign of this bug? No — most of the time it genuinely means there’s nothing to fix. Only treat it as suspicious when dart analyze is actively showing fixable-looking warnings (ones with a “Try replacing…” suggestion) at the same time.
Does this affect dart fix --apply the same way as --dry-run? Yes, both commands share the same underlying fix computation, so if --dry-run reports nothing, --apply won’t do anything either.
Will upgrading Dart or Flutter itself fix this? Possibly, since this is a known, actively-discussed behavior in the Dart SDK issue tracker — worth checking your Dart version against recent SDK releases if you’re hitting this often on a long-lived project.
Is manually fixing deprecated code risky? Not inherently, but always run flutter analyze after manual changes to confirm you haven’t introduced a new issue, same as you would after any automated fix.
Editor’s Opinion
genuinely one of the more frustrating quiet failures in the dart tooling because it doesn’t error, it just confidently tells you theres nothing to do when there clearly is. the new-file test is worth doing early if something feels off, saved me from assuming my config was broken when it wasnt. manual fixing sucks but its faster than chasing a tooling bug that isnt on you to solve
