In Flutter, why does Scaffold.of(context) throw when called from a button in the build method that creates that Scaffold, and how do you fix it?
answer
- whose context is it
- the builder's context sits above
- lookups only walk upward
- Builder gives an inner context
- or extract a child widget
basics
~20 sThe build method's context belongs to the widget that builds the Scaffold, so it sits above that Scaffold and the upward lookup never meets it. Use a Builder or an extracted child widget to get a context below the Scaffold.
solid answer
~50 sA widget's context is the parent of everything its `build` returns. When a `build` method creates a `Scaffold` and a button in that same method calls `Scaffold.of(context)`, the lookup starts at the outer widget's element, above the `Scaffold`, and walks toward the root, so it finds nothing and throws 'Scaffold.of() called with a context that does not contain a Scaffold.' The fixes the error message itself lists are: wrap the button in a `Builder` and use the builder's context; split the build into widgets so the inner widget has its own context under the `Scaffold`, which the message calls more efficient; or, less elegantly, give the `Scaffold` a `GlobalKey`. The same trap hits `Navigator.of` with the context of the widget that builds `MaterialApp`. Snackbars no longer have this problem: since Flutter 2.0 they go through `ScaffoldMessenger`, which `MaterialApp` places above your screens.
code
dart · 22 linesimport 'package:flutter/material.dart';
class LoanScreen extends StatelessWidget {
const LoanScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My loans')),
drawer: const Drawer(child: Text('Renewal history')),
body: Builder(
// This context belongs to the Builder, which is below the Scaffold.
builder: (innerContext) => TextButton(
onPressed: () => Scaffold.of(innerContext).openDrawer(),
child: const Text('Show history'),
),
),
// Using the outer `context` instead would throw:
// Scaffold.of() called with a context that does not contain a Scaffold.
);
}
}go deeper
Recall that the build method's own context sits above what it builds, and that a Builder gives you a context underneath.
Explain the upward-only lookup, why State.context is the same position, the three fixes the error lists, and why ScaffoldMessenger avoids the problem for snackbars.
Recognise the silent variants, such as Theme.of returning an outer theme, and steer reviews toward extracted widgets instead of Builder sprawl or GlobalKeys.
Set conventions for where screen-level services such as messengers and navigators live so feature code rarely needs to reason about context position at all.
## The failing code A library-loan screen has a drawer with renewal history. The screen's `build` returns `Scaffold(drawer: ..., body: ...)`, and inside the body a button calls `Scaffold.of(context).openDrawer()`. Tapping it throws: 'Scaffold.of() called with a context that does not contain a Scaffold.' The message's description continues: this usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold. ## Why the lookup misses - Every widget has its own `BuildContext`, which is its element. - The `context` parameter of a `build` method is the context of the widget that owns that method. - Everything `build` returns, including the `Scaffold`, becomes a **descendant** of that context. - `Scaffold.of` calls `findAncestorStateOfType<ScaffoldState>()`, which walks parent links **upward** only. The closure in `onPressed` captured the outer `context`, so the walk starts above the `Scaffold` and can never reach it. Using `State.context` in a `StatefulWidget` changes nothing; it is the same element. ## The fixes The framework's error message lists three: 1. **Use a `Builder`**, which the message calls the simplest. Wrap the button in `Builder(builder: (context) => ...)`; the inner `context` belongs to the `Builder`, which sits under the `Scaffold`. 2. **Split the build into widgets**, which the message calls more efficient. Move the button into its own widget class placed inside the `Scaffold`; its context is below the `Scaffold`. 3. **Use a `GlobalKey<ScaffoldState>`** on the `Scaffold` and call `key.currentState`. The message calls it less elegant but more expedient; the key mechanics belong to the keys topic. `Scaffold.maybeOf(context)` does not fix anything: it returns `null` instead of throwing, which only hides the miss. ## The same trap elsewhere | Call | Wrong context | Error or symptom | |---|---|---| | `Scaffold.of(context)` | Widget that builds the `Scaffold` | 'Scaffold.of() called with a context that does not contain a Scaffold.' | | `Navigator.of(context)` | Widget that builds `MaterialApp` | 'Navigator operation requested with a context that does not include a Navigator.' | | `Theme.of(context)` | Widget that wraps its subtree in a new `Theme` | No error, but returns the outer theme instead of the new one | The `Theme` row is the quiet variant: the lookup succeeds but returns the wrong ancestor, which the `BuildContext` documentation uses as its own example. ## Why snackbars stopped failing Before Flutter 2.0, snackbars were shown with `Scaffold.of(context).showSnackBar`, and this trap hit every beginner. The API moved to `ScaffoldMessenger`, and `MaterialApp` inserts a root `ScaffoldMessenger` above all routes. `ScaffoldMessenger.of(context)` from the screen's own build context therefore finds it, and the messenger shows the snackbar on the current `Scaffold`. `ScaffoldState` no longer has a `showSnackBar` method at all. ## Checklist - Ask where the context you are using sits relative to the widget you want. - Prefer extracting a small widget; reach for `Builder` for one-off inline cases. - Do not silence the error with `maybeOf`.
- Does the same trap apply to Navigator.of?Yes. If the widget that builds `MaterialApp` calls `Navigator.of(context)` with its own build context, the lookup starts above the `Navigator` that `MaterialApp` creates and debug builds report 'Navigator operation requested with a context that does not include a Navigator.' Use a context from inside the app's home or a route, where the `Navigator` is an ancestor.
- Why does the error message call splitting into widgets more efficient than a Builder?Both give a context below the `Scaffold`, but an extracted widget class is a real boundary: it can be `const`, skipped when unchanged and rebuilt on its own, and it keeps the screen's `build` shorter. A `Builder` only introduces a context and still reruns with its parent, which makes it fine for small inline cases.
saying these in an interview costs you the question
- Scaffold.of simply returns null when no Scaffold is found
- In a StatefulWidget, State.context is below the Scaffold its build returns
- Lookups also search the widgets returned by the current build
- Switching to Scaffold.maybeOf is the proper fix for the error
- Snackbars still have to be shown through Scaffold.of(context)