sinelaw/fresh · error

not inside a Fresh session; set --session

Error message

not inside a Fresh session; set --session <id> (or run inside a Fresh workspace so $FRESH_SESSION is set)

What it means

Thrown by resolve_cmd_socket when no session id is available: neither --session was given nor $FRESH_SESSION is set to a non-empty value. Command-channel subcommands (cmd/script) need a session to locate the editor's control socket.

Solutions

  1. Pass the id explicitly: `fresh --session <id> --cmd ...`.
  2. Run the command from a shell launched inside a Fresh workspace so $FRESH_SESSION is set.
  3. Check `echo $FRESH_SESSION`; if empty, export it with the running editor's session id.

Example fix

// before
fresh --cmd split right
// after
fresh --session my-session --cmd split right
Defensive patterns

Strategy: validation

Validate before calling

const session = process.env.FRESH_SESSION;
if (!session || !session.trim()) {
  console.error('FRESH_SESSION unset: pass --session <id> or run inside a Fresh workspace');
  process.exit(1);
}

Prevention

When it happens

Trigger: Running `fresh --cmd ...` or `fresh --script-file ...` in a plain shell where FRESH_SESSION is unset, or with `--session ""` / whitespace, without launching from inside a Fresh-spawned workspace shell.

Common situations: Calling fresh CLI helpers from cron/systemd/CI where the environment is stripped; opening a new terminal instead of the workspace shell; forgetting --session after copying a command out of docs.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

/// 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)"
            ),
        },
    };

    let socket_paths = resolve_session(Some(&session))?;
    socket_paths.cleanup_if_stale();
    match socket_paths.probe_server() {
        ServerLiveness::Alive => Ok(socket_paths),
        // Denied rather than absent. Say so, and say what to do: a caller that
        // can re-run outside its sandbox (an agent with an escalation path)
        // can act on this, whereas "no running editor" sends it hunting for a
        // stale session that is in fact alive and well.
        ServerLiveness::Unreachable => Err(socket_denied_error(&session, &socket_paths)),
        ServerLiveness::Dead => {
            anyhow::bail!("no running Fresh editor for session '{}'", session)
        }

View on GitHub (pinned to 67894ca546)