sinelaw/fresh · error

cannot reach the Fresh editor for session

Error message

cannot reach the Fresh editor for session '{}': its control socket ({}) could not be reached because connecting to it was denied. The editor is most likely running — the socket simply lives outside this process's sandbox. Re-run this command outside the sandbox.

What it means

Produced by `socket_denied_error` when connecting to the session's control socket fails with a permission/denied error: the socket file exists and the editor is almost certainly alive, but this process's sandbox (e.g. an agent sandbox) forbids reaching it. Fresh deliberately worded the message as an actionable instruction for automated agents: re-run the command outside the sandbox.

Solutions

  1. Re-run the command outside the sandbox, as the message instructs.
  2. If you control the sandbox policy, allow connect access to the control socket path (socket_paths.control).
  3. Verify user/permissions on the socket file if not sandbox-related (ls -l, chown/chmod as needed).

Example fix

// before (agent sandboxed, fails)
// inside sandbox: fresh-cli open foo.rs
// after: escape the sandbox for this one command
// $ fresh-cli open foo.rs   (run in the host shell, not the sandboxed tool)
Defensive patterns

Strategy: fallback

Validate before calling

fn can_reach_socket(p: &std::path::Path) -> bool {
    std::os::unix::net::UnixStream::connect(p).is_ok()
}

Try / catch

match run_cmd() {
    Err(e) if e.to_string().contains("connecting to it was denied") => {
        eprintln!("hint: re-run outside the sandbox");
        std::process::exit(2);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling any Fresh CLI command that targets an existing session (`FRESH_SESSION`) from inside a sandboxed process whose connect() to the control socket path is denied by the sandbox policy.

Common situations: Running CLI commands from within an AI coding agent's sandboxed shell; container/seccomp/landlock rules blocking unix-socket connect; running as a different user without rights to the socket file.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

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

        rest.push(tokens[i]);
        i += 1;
    }
    (session, rest)
}

/// Resolve the control socket for a command-channel verb.
///
/// The default target is the current workspace, named by `$FRESH_SESSION`;
/// `--session <id>` overrides it. Unlike `run_open_files_command`, this never
/// spawns a daemon — these verbs only make sense against a live editor, so a
/// missing session or dead server is a hard error.
/// The error for "the socket is there, but this process may not reach it".
///
/// Worded so the reader can act: an agent that can re-run outside its sandbox
/// needs to be told that is the fix, and told it in terms it can match on. The
/// injected "Teach Fresh CLI" contract points at this phrasing.
fn socket_denied_error(session: &str, socket_paths: &SocketPaths) -> anyhow::Error {
    anyhow::anyhow!(
        "cannot reach the Fresh editor for session '{}': its control socket ({}) \
         could not be reached because connecting to it was denied. The editor is \
         most likely running — the socket simply lives outside this process's \
         sandbox. Re-run this command outside the sandbox.",
        session,
        socket_paths.control.display(),
    )
}

fn resolve_cmd_socket(session_override: Option<&str>) -> AnyhowResult<SocketPaths> {
    let session = match session_override {
        Some(s) if !s.trim().is_empty() => s.to_string(),
        _ => match std::env::var("FRESH_SESSION") {
            Ok(s) if !s.trim().is_empty() => s,
            _ => anyhow::bail!(
                "not inside a Fresh session; set --session <id> (or run inside a \
                 Fresh workspace so $FRESH_SESSION is set)"
            ),

View on GitHub (pinned to 67894ca546)