sinelaw/fresh · error

the Fresh editor accepted the connection but did not answer…

Error message

the Fresh editor accepted the connection but did not answer within {:?}. It may be busy, or running a build without command-channel support; raise the wait with FRESH_CMD_TIMEOUT_MS if it is merely slow.

What it means

Mapped by `cmd_read_error` when the bounded read on the command channel returns `ErrorKind::TimedOut`: the editor accepted the connection but never sent a reply within `cmd_reply_timeout()` (configurable via FRESH_CMD_TIMEOUT_MS). Fresh distinguishes this from a refused/denied connection so users know the editor is alive but unresponsive on the command channel.

Solutions

  1. Set FRESH_CMD_TIMEOUT_MS to a larger value and retry if the editor is merely slow.
  2. Confirm the running editor build supports the command channel; restart it with a current build.
  3. Check whether the editor is blocked (modal dialog, hung task) and resolve that, then retry.
  4. Retry the command once the editor is idle.

Example fix

// before: default timeout too low
$ fresh-cli cmd "save-all"   # times out at default
// after: raise the wait
$ FRESH_CMD_TIMEOUT_MS=10000 fresh-cli cmd "save-all"
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: confirm the editor drains the command channel quickly
fn responds_quickly(p: &std::path::Path, ms: u64) -> bool {
    // attempt a cheap ping with a short deadline
    ping_with_timeout(p, std::time::Duration::from_millis(ms)).is_ok()
}

Try / catch

match send_command(cmd) {
    Err(e) if e.to_string().contains("did not answer within") => {
        std::env::set_var("FRESH_CMD_TIMEOUT_MS", "10000");
        retry_once(cmd)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: Sending a command to a running editor whose event loop doesn't drain the control socket within the timeout — notably a build of Fresh without command-channel support, or one busy with a long operation.

Common situations: Older/newer editor build lacking the command channel; editor blocked on a modal prompt or long-running task; default timeout too short on a heavily loaded machine.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/34cf83a00a27fde4. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/main.rs:3605

/// The default wait: enough for any command that answers off the editor thread.
fn cmd_reply_timeout() -> std::time::Duration {
    cmd_reply_timeout_or(std::time::Duration::from_secs(10))
}

/// The wait for a command that builds something first. A workspace create adds
/// a git worktree and starts an agent, which on a large repository is seconds,
/// not milliseconds — timing that out and reporting failure would be wrong
/// about a create that is merely still running.
fn cmd_build_timeout() -> std::time::Duration {
    cmd_reply_timeout_or(std::time::Duration::from_secs(180))
}

/// Turn a bounded-read failure into an actionable message. A timeout here means
/// the editor accepted the connection but never answered — the signature of a
/// build whose event loop doesn't drain the control socket.
fn cmd_read_error(e: std::io::Error) -> anyhow::Error {
    if e.kind() == std::io::ErrorKind::TimedOut {
        anyhow::anyhow!(
            "the Fresh editor accepted the connection but did not answer within {:?}. \
             It may be busy, or running a build without command-channel support; \
             raise the wait with FRESH_CMD_TIMEOUT_MS if it is merely slow.",
            cmd_reply_timeout()
        )
    } else {
        anyhow::Error::from(e)
    }
}

/// A live command-channel connection: the socket plus the reader that carries
/// bytes buffered between replies. One reader for the whole exchange — a fresh
/// one per read would drop anything that arrived in the same chunk as the
/// previous message.
struct CmdConnection {
    conn: fresh::server::ipc::ClientConnection,
    reader: fresh::server::ipc::ControlReader,
}

View on GitHub (pinned to 67894ca546)