always-pass-global-key

Path
lint/correctness/always-pass-global-key
Default
Off, opt in
Origin
Falcon
Domain
flutter
Rule
4 of 512
flutter

Keep GlobalKeys stable and pass owned State fields to widgets.

Reports nonconstant GlobalKey-subtype constructors directly in widget key arguments, including outside State classes. Value-stable GlobalObjectKeys, constant keys and cached field/top-level initializers are exempt. Closures inside those initializers are still checked. Stored keys are checked only for concrete Flutter State classes: abstract bases and injected fields are skipped. Passing a field anywhere in a call argument counts conservatively, since helpers may attach it to a widget. Shadowed locals and currentState/currentContext receiver reads do not count as passing the key.

Invalid

example.dartdart
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as f;
typedef FormKey = GlobalKey;
class Missing extends State<Widget> {
  final _first = GlobalKey();
  final GlobalKey _second = GlobalKey();
  final _third = f.GlobalKey();
  final _fourth = LabeledGlobalKey('fourth');
  final _fifth = FormKey();
  final _shadowed = GlobalKey();
  final _stateRead = GlobalKey();
  final _contextRead = GlobalKey();
  void inspect() {
    observe(_stateRead.currentState);
    observe(this._contextRead.currentContext);
  }
  Widget build() {
    final _shadowed = GlobalKey();
    return IconButton(key: _shadowed);
  }
}
void observe(Object? value) {}
Pass this `GlobalKey` field to a widget.
4class Missing extends State<Widget> {
5 final _first = GlobalKey();
Pass this `GlobalKey` field to a widget.
5 final _first = GlobalKey();
6 final GlobalKey _second = GlobalKey();
Pass this `GlobalKey` field to a widget.
6 final GlobalKey _second = GlobalKey();
7 final _third = f.GlobalKey();
Pass this `GlobalKey` field to a widget.
7 final _third = f.GlobalKey();
8 final _fourth = LabeledGlobalKey('fourth');
Pass this `GlobalKey` field to a widget.
8 final _fourth = LabeledGlobalKey('fourth');
9 final _fifth = FormKey();
Pass this `GlobalKey` field to a widget.
9 final _fifth = FormKey();
10 final _shadowed = GlobalKey();
Pass this `GlobalKey` field to a widget.
10 final _shadowed = GlobalKey();
11 final _stateRead = GlobalKey();
Pass this `GlobalKey` field to a widget.
11 final _stateRead = GlobalKey();
12 final _contextRead = GlobalKey();

Valid

example.dartdart
import 'package:flutter/material.dart';
class Used extends State<Widget> {
  final _direct = GlobalKey();
  final _helper = GlobalKey();
  final _conditional = GlobalKey();
  final _inherited = GlobalKey();
  final GlobalKey injected;
  Used(this.injected);
  Widget first() => IconButton(key: this._direct);
  void second() => attach(_helper);
  void third(bool choose) => attach(choose ? _conditional : null);
}
class Child extends Used {
  Child(GlobalKey key) : super(key);
  void attachInherited() => attach(_inherited);
}
abstract class Base extends State<Widget> {
  final inherited = GlobalKey();
}
class Controller { final key = GlobalKey(); }
class Wrapper extends Widget { final key = GlobalKey(); }
void attach(Object? key) {}
void locals() { final local = GlobalKey(); }

Configure always-pass-global-key

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "correctness": {
        "always-pass-global-key": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/correctness/always-pass-global-key: <reason>