Flutter Future, stream, controller, and widget lifecycle
A tool-agnostic recipe to cancel subscriptions and dispose controllers and async work with the owning widget or service. It supports a read-only audit and, when explicitly authorized, a narrow remediation.
When to use it
Use this recipe when the operator’s specific objective is to cancel subscriptions and dispose controllers and async work with the owning widget or service. Prefer a narrower CVE, scanner-finding, security-audit, or compliance-evidence recipe when that is the operator’s actual job.
Inputs
- Repository root and the files, package, service, or module in scope.
- Requested mode:
auditor explicitly authorizedfix. - Supported runtime, compiler, framework, operating-system, and deployment versions inferred from repository files.
- Existing formatter, compiler, analyzer, test, build, and package-manager commands.
- Public API, compatibility, performance, generated-code, vendor, and migration constraints.
The prompt
You are running the Security Recipes code-hygiene workflow `code-hygiene.dart-flutter.flutter-future-stream-controller-and-widget-lifecycle`.
Start read-only. Do not edit files until the operator explicitly authorizes a fix.
Use repository configuration and installed tool versions as authoritative; do not impose a new style or toolchain.
### Scope
Your bounded objective is to cancel subscriptions and dispose controllers and async work with the owning widget or service.
Inspect only operator-scoped, first-party source and configuration. Exclude generated, vendored, minified, fixture snapshot, lock history, and migration history unless explicitly included.
### Detection
- Trace subscriptions, timers, controllers, focus nodes, animations, futures, mounted checks, and dispose ordering.
- Find callbacks that call setState after teardown or retain State objects.
- Record file and symbol evidence for every candidate. Mark uncertain or dynamically reachable behavior instead of guessing.
### Fix, only when authorized
- Assign lifecycle ownership, cancel or dispose symmetrically, and guard unavoidable asynchronous completion.
- Keep the diff limited to the proven issue and its focused tests. Preserve public behavior, API compatibility, and repository conventions.
- Do not add or broaden suppressions, weaken diagnostics, mass-format unrelated files, upgrade dependencies, or mutate external state.
### Verification
- Run widget tests for mount, update, navigation away, cancellation, error, and repeated creation.
- Compare diagnostic counts and relevant behavior before and after. Report every command, result, and check that could not run.
### Stop conditions
- Stop if ownership belongs to a state-management container whose lifecycle is not visible.
- Stop and hand off to a focused security recipe if evidence indicates a vulnerability, secret exposure, authorization failure, injection path, or named CVE.
- Stop rather than widening scope when the safe result requires architecture, product, compliance, operational, or data-owner decisions.
Output contract
- Scope and repository evidence reviewed.
- A candidate table with file or symbol, evidence, confidence, and disposition.
- In audit mode: no edits, plus the smallest safe next action for each confirmed item.
- In fix mode: one bounded patch, focused regression coverage, and no unrelated cleanup.
- Commands run, results, remaining uncertainty, and any stop-condition handoff.
Verification
- Run widget tests for mount, update, navigation away, cancellation, error, and repeated creation.
- Confirm that diagnostic configuration, suppressions, public interfaces, generated files, vendored files, and dependencies did not change outside the authorized scope.
- Review the final diff for behavior changes and run the repository’s focused checks before broader suites.
Guardrails
- Read-only until edits are explicitly authorized.
- Do not deploy, publish, rotate secrets, alter cloud or database state, change CI permissions, or open external tickets.
- Do not hide debt by disabling rules, adding retries or sleeps, weakening tests, broadening ignores, or lowering warning levels.
- Treat generated, vendored, minified, migration-history, and fixture-snapshot files as out of scope unless explicitly named.
- Stop if ownership belongs to a state-management container whose lifecycle is not visible.
Related recipes
- Dart analyzer, null-safety, and ignore debt
- Lint warning baseline and budget
- Browse all code-hygiene recipes
References
- NIST SP 800-218 Secure Software Development Framework 1.1 — NIST
- Dart analysis options — Dart project
- Dart asynchronous programming — Dart project
- Flutter State dispose lifecycle — Flutter project