`stellar doctor` hangs indefinitely when an executable on PATH never exits

Open
#2,676 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
55/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
rust
Domain
cli

Research direction

Start with the run_version code introduced by #2670 and trace how find_installs and summarize_versions handle an executable that does not answer. Bound each version probe, ensure an expired child is killed and reaped, and decide whether timeouts need distinct reporting. Verify that a hung executable no longer blocks doctor and is reported through the existing unknown-version path.

Written by the indexing model from the issue text.

Description

Scope

This concerns code introduced by #2670, which is still open — run_version is not on main today. Filing it separately because the fix is a behavioral change that should not ride along inside a diagnostics-wording PR, and because the review thread that raised it currently reads as resolved when it is not.

What happens

doctor probes every Stellar CLI executable it finds on PATH to read its version. The probe spawns a child process and waits for it with no upper bound:

fn run_version(path: &Path, args: &[&str]) -> Option<String> {
    let output = Command::new(path).args(args).output().ok()?;

    if output.status.success() {
        Some(String::from_utf8_lossy(&output.stdout).into_owned())
    } else {
        None
    }
}

Command::output() blocks until the child exits and its stdout/stderr reach EOF. If any matching executable on PATH never exits — a stale shell wrapper, a broken install, a script blocked on stdin, a binary waiting on a network call — doctor hangs indefinitely with no output and no way to tell the user which executable is responsible.

It is reached twice per discovered executable — once for version --only-version and once for the --version banner fallback — so a single bad entry on PATH is enough to wedge the command.

Why it matters here specifically

doctor is the command a user runs because something is already wrong with their installation. A wedged PATH entry is exactly the kind of broken state it exists to diagnose, and it is the one state in which the command cannot report anything at all.

There is also an internal irony worth naming: the surrounding code already models "this executable did not answer" as a first-class outcome. find_installs returns Option<String> per executable, and summarize_versions distinguishes an observed version disagreement from executables that could not be asked. A timed-out probe fits that existing vocabulary exactly — it is an executable that did not answer — so the reporting side needs no new concepts.

Suggested fix

Bound the probe: spawn the child, wait with a short timeout (a couple of seconds is generous for --version), and on expiry kill and reap it, returning None so the executable is reported as unknown-version through the path that already exists for that case. Reaping matters — dropping a Child does not kill it, so a naive timeout leaves the process behind.

Worth deciding as part of the fix whether a timed-out probe should be reported distinctly from one that failed to spawn or exited non-zero. Both are "did not answer", but only the timeout points at an executable that is itself hung, which is actionable information for the user.

Credit

Originally raised by Copilot in review on #2670: https://github.com/stellar/stellar-cli/pull/2670#discussion_r3715688791

Dominant language
Rust
Stars
123
Forks
141
Avg merge
2d 21h
Merged PRs (30d)
17

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from stellar/stellar-cli

All issues in stellar/stellar-cli

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.