# Flutter: “LateInitializationError: Field '_controller' has not been initialized”

> LateInitializationError: Field has not been initialized. A late variable was read before it was set. Set it in initState or make it nullable.

Canonical: https://app369.com/fix/flutter-lateinitializationerror-field-has-not-been-initialized/
Last updated: 2026-11-08

The app shows a red error screen or crashes on start, and the log says LateInitializationError: Field '_controller' has not been initialized, or Local 'x' has not been initialized. A variable declared with late was read before any code gave it a value. Dart checks late variables when they are read, so the compiler could not warn you. The name in quotes is the variable to look for.

**Short answer**

Find the variable named in the error and the stack trace line that reads it. Then give it a value before that line runs: in initState, not in an async method that finishes later, or where it is declared. If it can really be missing for a while, drop late, make it nullable (Type?) and check for null where it is read. If you added the field while the app was running, do a hot restart first: hot reload keeps the screens already open, so their initState does not run again.

## **Why the variable has no value yet, and the fix**

1. 01 ### **Set in an async method, read in build**
  > “If you fail to initialize a late variable, a runtime error occurs when the variable is used.” [**Dart, Variables: late variables**](https://dart.dev/language/variables) initState calls an async _init() that awaits something, then sets the late field. build runs right after initState, before the await finishes, and reads the field. Make the field nullable and show a loader until it is set, or keep the Future and use a FutureBuilder.```
VideoPlayerController? _controller;

Future<void> _init() async {
  final c = VideoPlayerController.networkUrl(Uri.parse(widget.videoUrl));
  await c.initialize();
  if (!mounted) return;
  setState(() => _controller = c);
}

@override
Widget build(BuildContext context) {
  final c = _controller;
  if (c == null) return const CircularProgressIndicator();
  return VideoPlayer(c);
}

@override
void dispose() {
  _controller?.dispose();
  super.dispose();
}
```
2. 02 ### **A field set on only some paths**
  > “When you mark a variable as late but initialize it at its declaration, then the initializer runs the first time the variable is used.” [**Dart, Variables: late variables**](https://dart.dev/language/variables) The field is set in an if branch, a callback, a listener or didChangeDependencies, and read on a path where that code never ran. Give it a value on every path before it is read, or initialize it where it is declared. A late field with an initializer runs that code the first time it is read, so it is never unset.```
// runs the first time _repo is read
late final _repo = UserRepository(widget.api);
```
3. 03 ### **late added to silence a null-safety error**
  > “every time the field is read, a runtime check is inserted to make sure it has been assigned a value. If it hasn't, an exception is thrown.” [**Dart, Understanding null safety**](https://dart.dev/null-safety/understanding-null-safety) Adding late makes the compiler error “Non-nullable instance field must be initialized” go away, but it moves the check to runtime. If the value can be missing at any point, the honest type is nullable: Type? with a check where it is read.

Checked against the vendor’s docs on November 8, 2026: [Dart: Variables (late variables)](https://dart.dev/language/variables); [Dart: Understanding null safety (late variables)](https://dart.dev/null-safety/understanding-null-safety); [Flutter: Hot reload](https://docs.flutter.dev/tools/hot-reload).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**Flutter “Null check operator used on a null value”**](https://app369.com/fix/flutter-null-check-operator-used-on-a-null-value/) · [**Flutter “type 'Null' is not a subtype of type 'String'”**](https://app369.com/fix/flutter-type-null-is-not-a-subtype-of-type-string/) · [**Flutter “Looking up a deactivated widget’s ancestor is unsafe”**](https://app369.com/fix/flutter-looking-up-a-deactivated-widgets-ancestor-is-unsafe/) · [**Dart “Bad state: No element”**](https://app369.com/fix/flutter-bad-state-no-element/)

Questions

## **More on this error**

<details>

<summary>**What does “Field has already been initialized” mean? **+</summary>

The opposite case: a late final field was assigned twice, usually because the assignment sits in build, a listener or a method that runs more than once. Assign it once, in initState or where it is declared, or drop final if the value really changes.

</details>

<details>

<summary>**Why does it only happen sometimes? **+</summary>

Timing. If the field is set after an await or a network call, a fast device or a cached response sets it before build reads it, and a slow one does not. Treat the value as possibly missing until it is set.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)