sigoden/aichat · error

Invalid prelude

Error message

Invalid prelude '{prelude}

What it means

Thrown by GlobalConfig::apply_prelude() when the configured prelude string (repl_prelude or cmd_prelude) does not match any expected form: it must be `role:<name>`, `session:<name>`, or `<session>:<role>`. Anything else (no colon, or an unknown prefix) produces "Invalid prelude '<prelude>'". The same message also wraps failures of use_role/use_session inside the prelude application.

Solutions

  1. Fix the prelude in config.yaml to one of the supported formats: `role:<name>`, `session:<name>`, or `<session>:<role>`.
  2. Verify the referenced role/session exists (list roles/sessions before setting the prelude).
  3. Remove the prelude entry to start with defaults.

Example fix

// config.yaml — before
repl_prelude: my-gpt-session
// after
repl_prelude: "my-session:my-role"
Defensive patterns

Strategy: validation

Validate before calling

fn prelude_ok(p: &str) -> bool { matches!(p.split_once(':'), Some(("role", _)) | Some(("session", _)) | Some((_, _))) }

Try / catch

if let Err(e) = config.write().apply_prelude() { eprintln!("Prelude skipped: {e}"); }

Prevention

When it happens

Trigger: Setting repl_prelude/cmd_prelude in config.yaml to a value without a `:` separator, an unknown prefix (e.g. `model:gpt-4`), or to a role/session name that use_role/use_session reject.

Common situations: Typos in config.yaml prelude values; copying an example using a different prefix; referencing a deleted session or role in the prelude.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/config/mod.rs:1646

            None => return Ok(()),
        };

        let err_msg = || format!("Invalid prelude '{prelude}");
        match prelude.split_once(':') {
            Some(("role", name)) => {
                self.use_role(name).with_context(err_msg)?;
            }
            Some(("session", name)) => {
                self.use_session(Some(name)).with_context(err_msg)?;
            }
            Some((session_name, role_name)) => {
                self.use_session(Some(session_name)).with_context(err_msg)?;
                if let Some(true) = self.session.as_ref().map(|v| v.is_empty()) {
                    self.use_role(role_name).with_context(err_msg)?;
                }
            }
            _ => {
                bail!("{}", err_msg())
            }
        }
        Ok(())
    }

    pub fn select_functions(&self, role: &Role) -> Option<Vec<FunctionDeclaration>> {
        let mut functions = vec![];
        if self.function_calling {
            if let Some(use_tools) = role.use_tools() {
                let mut tool_names: HashSet<String> = Default::default();
                let declaration_names: HashSet<String> = self
                    .functions
                    .declarations()
                    .iter()
                    .map(|v| v.name.to_string())
                    .collect();
                if use_tools == "all" {
                    tool_names.extend(declaration_names);

View on GitHub (pinned to 82976d349a)