sinelaw/fresh · error

server closed the connection before answering

Error message

server closed the connection before answering

What it means

Thrown when the control connection yielded no frames within the timeout (recv_within returned None), i.e. the server closed the connection before delivering a ScriptResult or Error. It indicates the editor dropped the client mid-request rather than answering it.

Solutions

  1. Check whether the editor is still running; restart it if it exited.
  2. Retry the command once the editor is confirmed alive.
  3. Look at the editor's logs/stderr for a panic around the time of the request.
  4. Reduce script complexity or split long operations to avoid editor-side crashes.

Example fix

// before
fresh --cmd quit &  fresh --cmd split right   # quit tears down conn mid-request
// after
fresh --cmd split right; fresh --cmd quit
Defensive patterns

Strategy: retry

Validate before calling

// ensure the editor is reachable before each submission
const { execSync } = require('child_process');
function alive(session) {
  try { execSync(`pgrep -f 'fresh.*${session}'`, { stdio: 'ignore' }); return true; }
  catch { return false; }
}
if (!alive(process.env.FRESH_SESSION)) { console.error('editor not running; refusing to send'); process.exit(1); }

Try / catch

// bash
for i in 1 2 3; do
  fresh --cmd split right && break
  rc=$?
  if [ $rc -ne 0 ]; then sleep 1; pgrep -f 'fresh' >/dev/null || { echo 'editor died'; exit 1; }; fi
done

Prevention

When it happens

Trigger: Editor process exiting/crashing while a --cmd/script request is in flight; the command channel being shut down; an editor-side panic tearing down the connection before a reply is sent.

Common situations: Editor quitting concurrently with the command; long-running script triggering a crash; editor killed by OOM or user close during the request; stale socket briefly connecting before teardown completes.

Related errors


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

Appendix: source

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

    }
    Ok(CmdConnection { conn, reader })
}

/// Read control replies until a `ScriptResult` arrives (or an error/EOF/timeout).
/// Returns `(ok, error, output)`.
fn read_script_result(
    conn: &mut CmdConnection,
    timeout: std::time::Duration,
) -> AnyhowResult<(bool, Option<String>, Option<String>)> {
    use fresh::server::protocol::ServerControl;
    loop {
        match conn.recv_within(timeout)? {
            Some(ServerControl::ScriptResult { ok, error, output }) => {
                return Ok((ok, error, output))
            }
            Some(ServerControl::Error { message }) => anyhow::bail!("server error: {}", message),
            Some(_) => continue,
            None => anyhow::bail!("server closed the connection before answering"),
        }
    }
}

/// Dispatch a `--cmd cmd ...` / `--cmd split ...` / `--cmd workspace ...` /
/// `--cmd agent ...` invocation against a running editor. `tokens` is the full
/// `--cmd` vector (leading verb included).
fn run_cmd_command(tokens: &[&str]) -> AnyhowResult<()> {
    let (session, rest) = extract_session_flag(tokens);
    let session = session.as_deref();

    match rest.first().copied() {
        Some("script") => {
            match &rest[1..] {
                ["run", from @ ..] => script_run(session, from),
                ["check", from @ ..] => script_check(from),
                ["api", query, flags @ ..] => script_api(query, flags),
                ["api"] => {

View on GitHub (pinned to 67894ca546)