sinelaw/fresh · error
Server error
Error message
Server error: {} What it means
During the CLI handshake in main.rs, the server replied with the `ServerControl::Error { message }` variant. Fresh forwards the server's own error text verbatim via `"Server error: {}"`, so the root cause is whatever the editor reported (bad session, rejected command, internal failure). The CLI cannot proceed past the handshake when the server rejects it.
Solutions
- Read the embedded message after 'Server error:' — it is the editor's own diagnostic and names the real problem.
- Check the editor's logs for the matching server-side error to get the stack/cause.
- Retry the same CLI command after fixing whatever the embedded message indicates.
- If the message indicates a protocol/feature issue, upgrade client and editor to matching versions.
Example fix
// before: treating the wrapper as the cause
match result { Err(e) => eprintln!("failed: {e}"), ... }
// after: surface the inner server message for tooling
if let Some(msg) = e.to_string().strip_prefix("Server error: ") {
eprintln!("editor rejected request: {msg}");
} Defensive patterns
Strategy: try-catch
Try / catch
match run_handshake() {
Err(e) if e.to_string().starts_with("Server error: ") => {
let detail = &e.to_string()["Server error: ".len()..];
eprintln!("editor rejected: {detail}");
}
Err(e) => return Err(e),
Ok(v) => Ok(v),
} Prevention
- Always surface the embedded message rather than only the wrapper text
- Check editor logs when a handshake reports a server-side error
- Validate requested files/sessions exist before sending the Hello
- Keep client and server versions aligned
When it happens
Trigger: Any handshake where the connected editor responds to the client Hello with `ServerControl::Error`; the message embedded in the error is produced server-side.
Common situations: Requesting an operation the running editor rejects; server hit an internal error while setting up the session; protocol accepted but the requested session/file failed validation on the server.
Related errors
- handshake with the Fresh editor failed
- server error
- Unexpected server response
- no running Fresh editor for session
- server closed the connection before answering
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/0959d6da61296117.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/main.rs:3369
let response = read_reply()?
.ok_or_else(|| anyhow::anyhow!("Server closed connection during handshake"))?;
match serde_json::from_str::<ServerControl>(&response)? {
ServerControl::Hello(server_hello) => {
if server_hello.protocol_version != PROTOCOL_VERSION {
eprintln!(
"Version mismatch: server is v{}",
server_hello.server_version
);
return Ok(false);
}
Ok(true)
}
ServerControl::VersionMismatch(mismatch) => {
eprintln!("Version mismatch: server is v{}", mismatch.server_version);
Ok(false)
}
ServerControl::Error { message } => Err(anyhow::anyhow!("Server error: {}", message)),
_ => Err(anyhow::anyhow!("Unexpected server response")),
}
}
/// When launched from inside Fresh's own embedded terminal, forward the
/// file/dir arguments to the parent editor (identified by `FRESH_SESSION`)
/// instead of starting a second editor in the terminal.
///
/// Returns:
/// - `Some(Ok(()))` — forwarded; the caller should exit.
/// - `None` — not a nested launch, nothing to forward, or the parent
/// socket is unreachable; the caller should launch inline as usual.
fn try_forward_nested(args: &Args) -> Option<AnyhowResult<()>> {
// Only plain interactive file/dir opens are forwarded. Subcommands,
// --server and --attach are already handled before we get here;
// --stdin pipes content into a real editor and can't be forwarded.
if args.server || args.attach || args.stdin || args.files.is_empty() {
return None;View on GitHub (pinned to 67894ca546)