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

  1. Read the inner message after "server error:" — it names the actual editor-side failure.
  2. Fix the --cmd arguments or the throwing line in your script accordingly.
  3. Confirm the command/feature exists in the running editor's version.
  4. 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

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


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)