facebook/flow · error

failed to get executable path

Error message

failed to get executable path

What it means

To compute the client/server build id, flow hashes the bytes of its own executable; `std::env::current_exe().expect("failed to get executable path")` panics when the OS cannot resolve the running binary's path. On Linux this resolves /proc/self/exe, so it fails when /proc is missing/restricted or when the binary file was deleted or replaced after the process started (the symlink then points to a deleted inode).

Source

Thrown at rust_port/crates/flow_common_build_id/src/lib.rs:18

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use std::sync::OnceLock;

use flow_common_xx as xx;

static BUILD_ID: OnceLock<String> = OnceLock::new();

pub fn get_build_id() -> String {
    BUILD_ID
        .get_or_init(|| {
            let mut state = xx::State::new(0);
            let executable = std::env::current_exe().expect("failed to get executable path");
            let contents = std::fs::read(&executable).unwrap_or_else(|err| {
                panic!(
                    "failed to read executable at {} for flow build id: {}",
                    executable.display(),
                    err
                )
            });
            state.update(&contents);
            let hash = format!("{:016x}", state.digest());
            hash
        })
        .clone()
}

View on GitHub (pinned to f88ac94bcf)

Solutions

  1. Restart the flow client/server after an upgrade so it runs the current binary path.
  2. Change deploy scripts to install via rename (write new file, `mv` over) instead of overwriting the running binary in place.
  3. Ensure /proc is mounted and /proc/self/exe is readable inside the container or sandbox.
  4. As a code fix, fall back to argv[0] or a build-time embedded id when current_exe errors.

Example fix

// before
let executable = std::env::current_exe().expect("failed to get executable path");

// after
let executable = std::env::current_exe().unwrap_or_else(|_| {
    std::path::PathBuf::from(std::env::args_os().next().unwrap_or_default())
});
Defensive patterns

Strategy: fallback

Validate before calling

// Cheap pre-check where feasible: the exe path must resolve to an existing file
fn exe_resolvable() -> bool {
    std::env::current_exe().map(|p| p.exists()).unwrap_or(false)
}

Try / catch

let executable = std::env::current_exe()
    .unwrap_or_else(|_| std::path::PathBuf::from(std::env::args_os().next().unwrap_or_default()));

Prevention

When it happens

Trigger: The flow binary is overwritten or unlinked while running — in-place `cp` during deploys, a package manager upgrade replacing the binary, cargo rebuilding over a still-running binary; containers/chroots without /proc mounted; seccomp/sandbox policies blocking /proc/self/exe.

Common situations: A long-lived flow daemon surviving an upgrade that removed the old binary (its /proc/PID/exe shows `(deleted)`); deploy scripts that overwrite binaries in place; minimal container images with procfs masked.

Related errors


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