facebook/flow · error

ensure_parsed_or_trigger_recheck failed

Error message

ensure_parsed_or_trigger_recheck failed

What it means

In the codemod runner's first merge pass, `flow_services_inference::type_service::ensure_parsed_or_trigger_recheck` parses the merge set and verifies nothing changed on disk since the run began. It returns `Err(RecheckError::Canceled(files))` when files were modified concurrently ("unexpected file changes"), and this expect converts that cancellation into a panic.

Source

Thrown at rust_port/crates/flow_codemods/src/utils/codemod_runner.rs:728

    {
        let _should_print = _options.profile;
        let reader = _transaction.clone();
        let get_dependent_files = |_: &flow_common_utils::graph::Graph<FileKey>,
                                   _: &flow_common_utils::graph::Graph<FileKey>,
                                   _: &BTreeSet<FileKey>|
         -> std::pin::Pin<
            Box<dyn std::future::Future<Output = BTreeSet<FileKey>>>,
        > { Box::pin(async { BTreeSet::new() }) };
        let (_dependency_info, _components, files_to_merge, _) =
            merge_targets(_env, _options, &(), get_dependent_files, &_roots).await;
        if let Some(pool) = _workers {
            flow_services_inference::type_service::ensure_parsed_or_trigger_recheck(
                pool,
                &reader,
                &Arc::new(_options.clone()),
                files_to_merge.clone().into_iter().collect(),
            )
            .expect("ensure_parsed_or_trigger_recheck failed");
        }
        let mutator = ();
        flow_hh_logger::info!("Merging {} files", files_to_merge.len());
        if let Some(pool) = _workers {
            let _merge_results = flow_services_inference::merge_service::merge_runner(
                pool,
                &reader,
                _options,
                false, // for_find_all_refs
                _dependency_info.sig_dependency_graph(),
                _components,
                &files_to_merge,
                move |_transaction: &flow_heap::parsing_heaps::Transaction,
                      _opts: &Options,
                      _for_find_all_refs: bool,
                      _component: vec1::Vec1<FileKey>| {
                    Ok(merge_job(
                        &mutator,

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Re-run the codemod — a one-off concurrent edit during the run is the usual cause.
  2. Quiesce other writers first: `flow stop`, close or pause the editor's autosave, finish git operations before starting.
  3. Never run two codemods (or a codemod plus a flow server) on the same root at once.
  4. If it persists, find the process rewriting files (inotify/audit tools) and pause it for the duration.

Example fix

// before
flow_services_inference::type_service::ensure_parsed_or_trigger_recheck(
    pool, &reader, &Arc::new(_options.clone()), files,
).expect("ensure_parsed_or_trigger_recheck failed");

// after
match flow_services_inference::type_service::ensure_parsed_or_trigger_recheck(
    pool, &reader, &Arc::new(_options.clone()), files,
) {
    Ok(()) => {}
    Err(flow_services_inference::type_service::RecheckError::Canceled(files)) => {
        eprintln!("{} files changed during the codemod run; re-run on a quiesced repo", files.len());
        std::process::exit(2);
    }
    Err(other) => panic!("ensure_parsed_or_trigger_recheck failed: {other:?}"),
}
Defensive patterns

Strategy: retry

Validate before calling

// Cheap staleness probe: mtimes must not change across a short interval before the run
fn files_look_stable(files: &[std::path::PathBuf]) -> bool {
    let snap = |fs: &[std::path::PathBuf]| fs.iter()
        .map(|p| p.metadata().ok().and_then(|m| m.modified().ok()))
        .collect::<Vec<_>>();
    let a = snap(files);
    std::thread::sleep(std::time::Duration::from_millis(500));
    a == snap(files)
}

Try / catch

match ensure_parsed_or_trigger_recheck(pool, &reader, &options, files) {
    Ok(()) => {}
    Err(RecheckError::Canceled(files)) => {
        // files changed mid-run: safe to re-run the codemod from scratch once the repo is quiet
        eprintln!("{} files changed during the run; retrying", files.len());
    }
    Err(other) => panic!("{other:?}"),
}

Prevention

When it happens

Trigger: An editor autosave, format-on-save, git checkout/pull/rebase, another flow process, or a second codemod rewrites one of the files between the codemod's initial parse and this merge step; watchman-style daemons touching the repo during a long run.

Common situations: Running codemods with the IDE open and autosave enabled; concurrent `flow server`/daemon on the same root; scripts that `git pull` while codemods run; two codemods launched in parallel.

Related errors


AI-assisted analysis of facebook/flow@f88ac94bcf (2026-08-20). Data as JSON: /api/errors/b8049bb0e32b4c61. Report an issue: GitHub.