Skip to content

prefer_correct_handler_name

v1.0.0WarningConfigurableClass Naming

This rule flags a method passed as an event handler that is not named _onSomething or _handleSomething.

A handler is the other half of the onTap:/onChanged: convention that prefer_correct_callback_field_name enforces on the parameter. When the parameter is onTap: and the method behind it is submit, the call site reads onTap: submit and the reader holds the mapping themselves; onTap: _onTap states it once.

Only a tear-off passed to an on... parameter is considered. A closure is not a named handler, a method called normally is not a handler at all, and a parameter that is not named on... gives the rule no anchor to judge by.

The prefix must start a new word, so _online does not satisfy on.

This rule is in the pedantic preset.

class Button {
Button({this.onTap});
final void Function()? onTap;
}
class CheckoutForm {
void _submit() {}
Button buildButton() => Button(onTap: _submit);
}
class CheckoutForm {
void _onTap() {}
Button buildButton() => Button(onTap: _onTap);
}

_handleTap is accepted too — handle is the second default prefix.

Only a tear-off passed to an on... parameter is judged

Section titled “Only a tear-off passed to an on... parameter is judged”

The rule needs both halves: a parameter named on..., and a bare method name as its value. Anything else gives it no anchor:

class Button {
Button({this.onTap, this.builder});
final void Function()? onTap;
final void Function()? builder;
}
class CheckoutForm {
void submit() {}
void run() {
// Not reported — a closure is not a named handler
Button(onTap: () => submit());
// Not reported — `builder` is not an `on...` parameter
Button(builder: submit);
// Not reported — called normally, not passed as a handler
submit();
}
}

_online does not satisfy on, because l is not the start of a new word:

class CheckoutForm {
void _online() {}
void _onLine() {}
void run() {
Button(onTap: _online); // LINT
Button(onTap: _onLine); // accepted
}
}

require_private: true — the default — means a handler must also start with an underscore, so onTap as a method name is reported while _onTap passes. Set it to false when your widgets expose their handlers:

rules:
prefer_correct_handler_name:
require_private: false
class CheckoutForm {
void onTap() {}
void run() {
Button(onTap: onTap); // accepted with `require_private: false`
}
}

additional_prefixes extends the defaults. Writing prefixes: instead replaces them, so on and handle stop being accepted unless you list them again:

rules:
prefer_correct_handler_name:
additional_prefixes: [process]
class CheckoutForm {
void _processTap() {}
void run() {
Button(onTap: _processTap); // accepted with the config above
}
}

This rule is in the pedantic preset, so it is enabled by preset: pedantic or by name:

many_lints.yaml
rules:
prefer_correct_handler_name:
enabled: true
analysis_options.yaml
many_lints:
rules:
prefer_correct_handler_name:
additional_prefixes: [process]
require_private: true
Option Type Default Description
prefixes list [on, handle] Accepted handler prefixes. Replaces the defaults
additional_prefixes list [] Prefixes to add without replacing the defaults
require_private bool true Whether a handler must also start with an underscore

Methods only. A top-level function or a local function passed as a handler is not reported — the value has to resolve to a method on a class.

Closures are invisible. onTap: () => submit() is never reported, however the method behind it is named.

No quick fix. Renaming a method touches every call site, which is a rename refactoring rather than a one-file edit.

To disable this rule:

many_lints.yaml
rules:
prefer_correct_handler_name: false

To keep the rule on but skip certain paths, use per-rule exclude.