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
- Check whether the editor is still running; restart it if it exited.
- Retry the command once the editor is confirmed alive.
- Look at the editor's logs/stderr for a panic around the time of the request.
- 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
- Don't send commands concurrently with quit/close operations.
- Retry idempotent commands once on connection drops.
- Watch editor logs for panics that tear down the command channel.
- Keep scripts short; long scripts increase the window for editor exit mid-request.
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
- server error
- no running Fresh editor for session
- handshake with the Fresh editor failed
- Server error
- Unexpected server response
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)