sigoden/aichat · error

Already in a session, please run '.exit session' first to…

Error message

Already in a session, please run '.exit session' first to exit the current session.

What it means

GlobalConfig::use_session (src/config/mod.rs:1075) refuses to start a new session while self.session is already Some, i.e. the REPL is already inside an active session. The library enforces at most one live session at a time and tells the user to exit it first. This is an explicit state-machine guard, not a resource failure.

Solutions

  1. Run `.exit session` (or exit_session) to close the current session, then call use_session again
  2. If you want to keep working, reuse the current session instead of starting a new one
  3. Check with `self.session.is_some()` / an equivalent accessor before attempting to start a session

Example fix

// before
config.write().use_session(Some("work"))?; // fails if already in a session
// after
{
    let mut cfg = config.write();
    if cfg.session.is_some() {
        cfg.exit_session()?;
    }
    cfg.use_session(Some("work"))?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn can_start_session(cfg: &GlobalConfig) -> bool {
    cfg.read().session.is_none()
}

Try / catch

if let Err(e) = config.write().use_session(Some("work")) {
    if e.to_string().contains("Already in a session") {
        config.write().exit_session()?;
        config.write().use_session(Some("work"))?;
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling `.session <name>` (or use_session) while a session is already active; invoking session start twice in a script without closing the first; a REPL hook that auto-starts a session colliding with a user-initiated `.session` command.

Common situations: Long-running REPL where the user forgot an earlier `.session` call; automation that issues `.session` on each command; recovering from a crashed wrapper that left session state logically open in the same process.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09). Data as JSON: /api/errors/f98b115f6898b0ed. Report an issue: GitHub.

Appendix: source

Thrown at src/config/mod.rs:1075

                }
            }
        }
        if with_builtin {
            names.extend(Role::list_builtin_role_names());
        }
        let mut names: Vec<_> = names.into_iter().collect();
        names.sort_unstable();
        names
    }

    pub fn has_role(name: &str) -> bool {
        let names = Self::list_roles(true);
        names.contains(&name.to_string())
    }

    pub fn use_session(&mut self, session_name: Option<&str>) -> Result<()> {
        if self.session.is_some() {
            bail!(
                "Already in a session, please run '.exit session' first to exit the current session."
            );
        }
        let mut session;
        match session_name {
            None | Some(TEMP_SESSION_NAME) => {
                let session_file = self.session_file(TEMP_SESSION_NAME);
                if session_file.exists() {
                    remove_file(session_file).with_context(|| {
                        format!("Failed to cleanup previous '{TEMP_SESSION_NAME}' session")
                    })?;
                }
                session = Some(Session::new(self, TEMP_SESSION_NAME));
            }
            Some(name) => {
                let session_path = self.session_file(name);
                if !session_path.exists() {
                    session = Some(Session::new(self, name));

View on GitHub (pinned to 82976d349a)