Skip to content

Improve error handling for missing native binaries - #2

Open
k-shan wants to merge 4 commits into
doramirdor:mainfrom
k-shan:fix/improve-native-binary-error-handling
Open

Improve error handling for missing native binaries#2
k-shan wants to merge 4 commits into
doramirdor:mainfrom
k-shan:fix/improve-native-binary-error-handling

Conversation

@k-shan

@k-shan k-shan commented Sep 4, 2026

Copy link
Copy Markdown

Summary

When Echo is installed without Xcode Command Line Tools or cmake, several things go wrong silently or with misleading error messages. This PR fixes three related issues:

  • Stop "Source not found" log spamcheck_dependencies() was calling ensure_swift_binary() on every status poll (~every 3s), logging a WARN each time in packaged builds where source .swift files don't ship. Now it just checks if the binary exists. Also downgraded the log to debug!.
  • Pre-check for git/cmake before whisper buildbuild_binary() now verifies git and cmake are installed before cloning or configuring whisper.cpp, with actionable error messages (e.g. "Install it with: brew install cmake") instead of a generic "Whisper is not set up."
  • Distinguish missing binary from permission errors — When the record binary doesn't exist, the error mapper was showing "Grant microphone access..." which is wrong. Now missing-binary errors say "Audio recorder binary is missing. Reinstall Echo or install Xcode Command Line Tools" while permission errors still point to System Settings.

Rust-only changes — no TypeScript/renderer changes.

Test plan

  • cargo test passes (147 tests, including 2 new error-mapping tests)
  • Verify in a packaged build that the log spam is gone
  • Verify that building whisper without cmake shows the new error message
  • Verify that triggering record without the binary shows "missing" not "microphone access"

🤖 Generated with Claude Code

Khugan Shanmugeswaran and others added 3 commits September 4, 2026 15:06
check_dependencies() now checks if the record binary exists directly
instead of calling ensure_swift_binary(), which attempts recompilation
on every call. In packaged builds where source .swift files don't ship,
this caused hundreds of WARN-level log entries every few seconds from
the onboarding status poller.

Also downgrade the "Source not found" log in ensure_swift_binary from
warn to debug — it's expected in packaged builds and not actionable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
build_binary() now verifies git and cmake are installed before cloning
or configuring. Without this, a missing cmake causes a confusing
"cmake failed: No such file or directory" that the error mapper rewrites
to the generic "Whisper is not set up" — hiding the actual fix.

The new error messages intentionally avoid the word "whisper" so they
pass through to_user_facing_error() verbatim, giving the user an
actionable install command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ages

When the record binary doesn't exist, the error mapper was showing
"Grant microphone access..." which is misleading — the real problem is
a missing binary, not a permission issue. Now errors containing
"unavailable", "not found", or "command not found" correctly say
"Audio recorder binary is missing" with an actionable fix. Permission-
related errors still point to System Settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@doramirdor doramirdor left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified on the branch: cargo test passes (147), no new clippy warnings. The shape of all three fixes is right — build_binary checks after the bin.exists() early return so there's no cost on the happy path, start() still compiles on demand so dropping ensure_swift_binary from check_dependencies doesn't break the dev flow, and both new error branches are covered by tests.

One blocker plus two minor notes inline.

Blocker: cmd_exists inherits the app's bare PATH, so the new pre-check will reject Homebrew cmake on machines where the build currently succeeds.

Minor: the most likely missing-binary spawn error still routes to the microphone-permission message, and check_dependencies now reports false during the first-launch compile window.

🤖 Generated with Claude Code

Ok(())
}

fn cmd_exists(name: &str) -> bool {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker — this ignores the PATH augmentation that every other subprocess spawn in the codebase does, so the new guard will falsely block working builds.

run_cmd directly below adds /opt/homebrew/bin:/usr/local/bin (same in parakeet.rs:283, refinement/cli.rs:10, codebase/analyzer.rs:62) precisely because a Finder-launched .app inherits /usr/bin:/bin:/usr/sbin:/sbin. cmd_exists inherits that bare PATH, so a Homebrew cmake at /opt/homebrew/bin/cmake is invisible and the check returns "cmake is not installed" on a machine where run_cmd would have found it fine. That's a regression, and it lands on exactly the packaged users this PR targets.

Hoist the PATH the file already builds:

fn build_path_env() -> String {
    format!("{}:/opt/homebrew/bin:/usr/local/bin", std::env::var("PATH").unwrap_or_default())
}

fn cmd_exists(name: &str) -> bool {
    Command::new(name)
        .arg("--version")
        .env("PATH", build_path_env())
        .output()
        .map(|o| o.status.success())
        .unwrap_or(false)
}

…and have run_cmd use build_path_env() too.

Nit while here: on a Mac without CLT, cmd_exists("git") runs the /usr/bin/git shim, which pops the system "install command line tools" dialog as a side effect of the check. Probably fine — arguably helpful — just worth knowing it isn't a silent probe.

Comment thread src-tauri/src/utils/errors.rs Outdated

if lower.contains("audio recorder") || lower.contains("record.swift") || lower.contains("rec: command not found") {
return "Audio recording is unavailable. Grant microphone access in System Settings → Privacy & Security → Microphone (and install Xcode Command Line Tools if prompted).".into();
if lower.contains("unavailable") || lower.contains("not found") || lower.contains("command not found") {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor — this misses the most likely missing-binary error, so the case the PR is fixing survives on the main path.

recorder.rs:71 produces Failed to start native audio recorder: No such file or directory (os error 2) when the spawn fails. That contains audio recorder but none of unavailable / not found / command not found, so it falls through to the permission message — the exact "Grant microphone access" mislabel this PR is removing.

if lower.contains("unavailable") || lower.contains("not found")
    || lower.contains("command not found") || lower.contains("no such file")
{


pub fn check_dependencies() -> (bool, String) {
if crate::utils::swift_binary::ensure_swift_binary("record", "scripts/record.swift") {
if crate::utils::swift_binary::get_binary_path("record").exists() {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor / FYI — right call for the log spam, but note the behavior change: check_dependencies no longer compiles, so on first launch it reports false for the window while ensure_swift_binary_async (lib.rs:2203) is still building the helper. Transient false negative in the health panel / tray until the async compile lands. Acceptable as-is, just shouldn't be a surprise later.

…rror mapper

cmd_exists now uses the same Homebrew-aware PATH as run_cmd so the
pre-build check for git/cmake doesn't false-reject on Finder-launched
.app bundles. The error mapper now matches "no such file" so a missing
recorder binary spawn failure routes to the correct user-facing message
instead of the microphone-permission one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants