sinelaw/fresh · error
server error
Error message
server error: {} What it means
While waiting for a ScriptResult, the client received a ServerControl::Error frame from the editor. The message is wrapped as "server error: <message>" — the inner message is the editor-side failure for the command/script that was submitted.
Solutions
- Read the inner message after "server error:" — it names the actual editor-side failure.
- Fix the --cmd arguments or the throwing line in your script accordingly.
- Confirm the command/feature exists in the running editor's version.
- Retry after correcting; errors here are per-request, not connection-level.
Example fix
// before fresh --cmd workspace togglee # typo → server error: unknown command // after fresh --cmd workspace toggle
Defensive patterns
Strategy: try-catch
Validate before calling
// validate --cmd tokens against known commands before sending
const KNOWN = ['split', 'workspace', 'agent', 'quit', 'ping'];
const cmd = process.argv[3];
if (!KNOWN.includes(cmd)) { console.error(`unknown --cmd '${cmd}'; valid: ${KNOWN.join(', ')}`); process.exit(1); } Try / catch
// rust
match read_control_reply(&mut conn, timeout) {
Ok((true, _, output)) => println!("{output}"),
Ok((false, Some(err), _)) => { eprintln!("command rejected: {err}"); std::process::exit(1); }
Err(e) if e.to_string().starts_with("server error") => { eprintln!("fix cmd/script: {e}"); std::process::exit(1); }
Err(e) => return Err(e),
} Prevention
- Check --cmd spelling against the documented command list.
- Keep scripts compatible with the running editor's API version.
- Validate layout arguments (splits, workspace names) before submitting.
- Treat the inner message as authoritative; fix that, not the wrapper text.
When it happens
Trigger: Any --cmd/--script submission where the editor-side handler errors: unknown command token, invalid arguments, a script that threw, or an operation rejected by the editor (e.g. command unavailable in the current state).
Common situations: Typo'd subcommand passed to --cmd; script using an API not present in the running editor; requesting a workspace/split operation that conflicts with current layout; agent tooling sending malformed commands.
Related errors
- server closed the connection before answering
- Server error
- no running Fresh editor for session
- handshake with the Fresh editor failed
- Unexpected server response
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/b31b3b2170c50cbf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/main.rs:3689
// client_handshake already printed the mismatch reason.
anyhow::bail!("handshake with the Fresh editor failed");
}
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),View on GitHub (pinned to 67894ca546)