Skip to content

[flutter_tools] BuildHooks depfile omits hook-produced asset files (LinkHooks already lists them) #186305

@bdero

Description

@bdero

When the per-package files produced by build hooks (e.g. DataAsset files) are removed from disk, flutter run and flutter build print Skipping target: build_hooks and proceed to the asset-bundling step, which then fails. The hook target is treated as up-to-date even though its real outputs are gone.

The cause is narrow: the existing LinkHooks target already declares hook-produced asset files as outputs in its depfile, but the BuildHooks target does not. Mirroring the LinkHooks pattern in BuildHooks closes the gap, and the existing outputMissing check at build_system/build_system.dart:1241-1246 handles the rest at no additional cost.

Steps to reproduce

  1. Use any project where a build hook registers a DataAsset. Run it once successfully so the hook caches a fresh build.
  2. Manually delete one of the produced asset files.
  3. flutter run -d <device>.

Observed (verbose):

Skipping target: build_hooks
...
Error detected in pubspec.yaml:
No file or variants found for asset: ...

Target debug_android_application failed: Exception: Failed to bundle asset files.

flutter clean does not help because it wipes build/ but leaves the .dart_tool/flutter_build/<hash>/native_assets.json cache, which still claims inputs are unchanged.

Where the asymmetry is

packages/flutter_tools/lib/src/build_system/targets/native_assets.dart.

LinkHooks.build includes hook-produced files in its depfile outputs at line 228-234:

final depfile = Depfile(
  <File>[for (final Uri dependency in result.dependencies) fileSystem.file(dependency)],
  <File>[
    fileSystem.file(dartHookResultJsonFile),
    for (final Uri uri in result.filesToBeBundled) fileSystem.file(uri),
  ],
);

BuildHooks.build does not, line 79-82:

final depfile = Depfile(
  <File>[for (final Uri dependency in dependencies) fileSystem.file(dependency)],
  <File>[fileSystem.file(dartBuildOutputJsonFile)],
);

So when a build hook produces a DataAsset and the consuming app later loses the asset file, BuildHooks' cache keeps claiming up-to-date because the only output it knows about (build_hooks_result.json) is still present.

Suggested fix

In BuildHooks.build, fold the hook's bundled files into the depfile outputs, matching the LinkHooks shape. The BuildResult from the hook protocol already carries the asset file URIs (the same filesToBeBundled view LinkHooks consumes), so this is plumbing that already exists at the layer above; it just needs to be propagated into the depfile.

A unit test should cover: BuildHooks runs once, declared output is deleted from disk, second run sees outputMissing for that path and re-runs.

Note for hook authors

This fix only catches missing outputs that were registered as hook-produced assets in the first place (typically DataAsset via output.assets.addEncodedAsset(DataAsset(...).encode())). Hooks that write into the consumer's build/ directory and rely on the consumer's pubspec flutter: assets: block sit outside this protocol and won't benefit; those hooks should migrate to registering their outputs through the hooks API for both correctness reasons (this) and asset path consistency (packages/<pkg>/<name> instead of consumer-relative paths).

Workaround

Until this lands, when you've nuked something a hook produces, you have to invalidate the input-hash cache by hand:

rm -rf .dart_tool packages/*/.dart_tool examples/flutter_app/.dart_tool \
       packages/flutter_scene/build examples/flutter_app/build
flutter pub get

flutter clean alone is not sufficient.

Flutter version

Flutter 3.44.0-1.0.pre-380 (channel master)

Reproducible on master.

Metadata

Metadata

Assignees

Labels

has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-toolOwned by Flutter Tool teamtoolAffects the "flutter" command-line tool. See also t: labels.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions