Fix flutter_gen/gen_l10n Import Error: Two Real Causes
You upgraded a localized app to a recent stable channel and every file that touches translations lights up red:
Target of URI doesn't exist: 'package:flutter_gen/gen_l10n/app_localizations.dart'.
Try creating the file referenced by the URI, or Try using a URI for a file that exists.
Two completely unrelated problems produce that identical line, and the fix for one does nothing for the other. That is why so many threads end with "I tried everything and it still doesn't work." Run this before you change anything:
grep -n "flutter_gen" pubspec.yaml
- Prints nothing → you have cause 1: the synthetic package is gone and your import path is stale.
- Prints a line → you have cause 2 on top of cause 1, and you must fix cause 2 first, or every other fix will look like it failed.
Cause 1: package:flutter_gen no longer exists
For years, flutter gen-l10n wrote app_localizations.dart into a synthetic package under .dart_tool/ and patched package_config.json so package:flutter_gen/... resolved to it. Nothing was ever on your source tree, which is exactly why the analyzer can't find it now.
The removal landed in stages:
- 3.28.0-0.0.pre — the tool stopped generating the synthetic package and stopped modifying
package_config.json. - 3.32.0 stable — synthetic generation is off by default (it followed the explicit-package-dependencies flag).
- 3.35 through current stable (3.47.x) — the option is gone for good.
synthetic-package: trueis now a hard tool exit:
l10n.yaml: Cannot enable "synthetic-package", this feature has been removed.
See http://flutter.dev/to/flutter-gen-deprecation.
And synthetic-package: false — the line half the internet still tells you to add — now only prints a warning:
l10n.yaml: The argument "synthetic-package" no longer has any effect and should be removed.
The flutter gen-l10n --help text on current stable is blunt about it: "DEPRECATED. This flag cannot be enabled and should be removed."
The l10n.yaml that works today
# l10n.yaml — Flutter 3.35+
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-dir: lib/l10n
output-class: AppLocalizations
nullable-getter: false
Notes on each key, because the defaults bite:
output-dirdefaults toarb-dirwhen omitted. Setting it explicitly makes the import path obvious to everyone reading the repo.nullable-getterdefaults totruefor backwards compatibility, soAppLocalizations.of(context)returnsAppLocalizations?and you sprinkle!everywhere. Set it tofalseand the generator does the null check for you.- If — and only if — you still need to build this repo on 3.24–3.32, keep
synthetic-package: falseand accept the deprecation warning on newer channels. On a 3.35+-only repo, delete the line.
If you want to sanity-check a config against the current option set, the free l10n.yaml generator writes one for you, and the complete l10n.yaml configuration guide covers the rest of the keys.
generate: true is still required
This one trips people who assume the whole generate mechanism died with the synthetic package. It didn't:
flutter:
uses-material-design: true
generate: true
Drop it and the tool refuses to run at all:
Attempted to generate localizations code without having the flutter: generate flag turned on.
Check pubspec.yaml and ensure that flutter: generate: true has been added and rebuild the project.
With generate: true, flutter run and flutter build regenerate localizations as part of the build; flutter gen-l10n just does it on demand.
The correct import line
The generated files are now ordinary files in lib/, so import them like any other file in your package:
// package: form — works from anywhere, including test/ and integration_test/
import 'package:my_app/l10n/app_localizations.dart';
// relative form — fine inside lib/, e.g. from lib/main.dart
import 'l10n/app_localizations.dart';
Replace my_app with the name: field from your pubspec.yaml. With nullable-getter: false, usage is clean:
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:my_app/l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Builder(
builder: (context) {
final l10n = AppLocalizations.of(context); // non-nullable
return Scaffold(body: Center(child: Text(l10n.helloWorld)));
},
),
);
}
}
Cause 2: flutter_gen: any in pubspec.yaml
Here is the part that wastes entire afternoons. When the analyzer can't resolve package:flutter_gen/..., VS Code offers an "Add dependency 'flutter_gen'" quick fix, and older dart fix --apply runs did it unprompted (see flutter/flutter#148949 — reported against 3.22.1 and since fixed, but the same line lives on in countless pubspecs and in copy-pasted advice). You end up with:
dependencies:
flutter:
sdk: flutter
flutter_gen: any # ← this is the trap
Pub happily resolves it, because flutter_gen is a real pub.dev package — it's FlutterGen, the asset/font/color code generator (5.15.0 at the time of writing), which has nothing whatsoever to do with localization. Worse: the published archive is a CLI package. It ships bin/flutter_gen_command.dart, an example/, and tests — there is no lib/ directory at all. A package with no lib/ can never satisfy a package:flutter_gen/... URI.
So after adding it you get: a successful pub get, a new transitive dependency you never wanted, and the exact same error message. Every subsequent fix appears to do nothing.
The fix is one deleted line:
dependencies:
flutter:
sdk: flutter
- flutter_gen: any
flutter pub get
flutter pub deps --style=compact | grep flutter_gen || echo "clean"
If you genuinely use FlutterGen for assets, it belongs in dev_dependencies (flutter_gen_runner) or as the global fluttergen CLI — and it still never provides gen_l10n/app_localizations.dart.
Migrate every import in the codebase at once
Don't hand-edit 80 files. Match on the directory prefix rather than the filename so a custom output-localization-file is covered too:
# macOS / BSD sed
grep -rl --include='*.dart' 'package:flutter_gen/gen_l10n/' lib test integration_test \
| xargs sed -i '' 's|package:flutter_gen/gen_l10n/|package:my_app/l10n/|g'
# Linux / GNU sed
grep -rl --include='*.dart' 'package:flutter_gen/gen_l10n/' lib test integration_test \
| xargs sed -i 's|package:flutter_gen/gen_l10n/|package:my_app/l10n/|g'
Swap my_app for your package name and l10n for your output-dir (minus the leading lib/). Then rebuild the world:
flutter clean
flutter pub get
flutter gen-l10n
flutter analyze
flutter clean matters more than it looks: a stale .dart_tool/package_config.json left over from the synthetic-package era can keep the old error alive after you've already fixed both causes.
Stop the IDE from putting it back
- Restart the analysis server after regenerating — in VS Code, Dart: Restart Analysis Server. The analyzer caches package resolution and will keep showing a resolved error long after the files are correct.
- Never accept the "Add dependency" quick fix for
flutter_gen. It is the single most common way this regression gets committed. - Diff your pubspec after bulk fixes:
dart fix --apply && git diff pubspec.yaml. Treat any new dependency from a lint fix as a bug. - Guard it in CI so a teammate's IDE can't reintroduce it:
# fails the build if flutter_gen is declared again
if grep -qE '^[[:space:]]+flutter_gen[[:space:]]*:' pubspec.yaml; then
echo "flutter_gen is back in pubspec.yaml — remove it" >&2
exit 1
fi
- If auto-import keeps proposing odd paths,
"dart.autoImportCompletions": false(defaulttrue) turns the feature off entirely — blunt, but effective on a repo that's mid-migration.
One more decision now that generation writes into lib/: either commit app_localizations*.dart (simplest, and keeps CI and IDEs happy on a fresh clone) or gitignore them and run flutter gen-l10n as an explicit CI step. Pick one and write it down — half-committed generated files are their own category of confusing.
While you're in there, check the ARB files
A migration like this is a good moment to look at what the generator is actually consuming. Two things commonly rot in a long-lived lib/l10n folder: keys that exist in app_en.arb and nowhere else, and ICU plural blocks that are missing a category the target language actually requires — Arabic needs zero/two/few/many, Polish and Russian need few/many, and a dropped category renders as the wrong string rather than throwing.
FlutterLocalisation is an ARB editor and translation-management platform built for exactly this: edit app_<locale>.arb files in a UI instead of hand-editing JSON, manage many locales side by side, and get ICU plural-syntax validation that flags a locale missing a plural category its language needs. The online ARB editor opens a file directly in the browser, and the blog has the rest of the migration story — including the step-by-step synthetic-package migration and the related "output-dir is required" error.
Try FlutterLocalisation free — bring the lib/l10n folder you just fixed and see what the validator finds.