rtk-ai/rtk · error

config.toml is not valid TOML

Error message

config.toml is not valid TOML: {e}

What it means

apply_recall_mode parses the user's config.toml with toml_edit before rewriting the retriever/tee sections. If the file content is not syntactically valid TOML, the parse fails and the function wraps the toml_edit error in this anyhow error.

Solutions

  1. Open config.toml and fix the TOML syntax error reported after the colon (line/column are included by toml_edit).
  2. Validate the file with a TOML linter or `python -c "import tomllib;tomllib.load(open('config.toml','rb'))"`.
  3. If unsure, back up and delete/recreate config.toml, then re-run the command to regenerate defaults.

Example fix

// before (broken)
retriever = sqlite
tee = 
// after
[retriever]
mode = "sqlite"
Defensive patterns

Strategy: try-catch

Validate before calling

import tomllib
with open('config.toml','rb') as f:
    tomllib.load(f)  # raises on invalid TOML before running rtk

Try / catch

match rtk_set_recall_mode(mode) {
    Err(e) if e.to_string().contains("not valid TOML") => {
        eprintln!("Fix config.toml first: {e}");
        // open editor / restore backup
    }
    Err(e) => return Err(e),
    Ok(_) => (),
}

Prevention

When it happens

Trigger: Calling set_recall_mode (or the internal apply_recall_mode in tests) while ~/.config/rtk/config.toml (or the config content passed in) contains a TOML syntax error: unclosed string, duplicate key, missing bracket on a table header, stray tab, etc.

Common situations: Hand-edited config.toml with a typo; a previous crashed/partial write; pasting JSON into a TOML file; merging conflicting edits leaving duplicated keys.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of rtk-ai/rtk@0924356b4c (2026-09-19). Data as JSON: /api/errors/53e72087b2f5abc6. Report an issue: GitHub.

Appendix: source

Thrown at src/core/config.rs:395

        }

        let content = toml::to_string_pretty(self)?;
        std::fs::write(&path, content)?;
        Ok(())
    }

    pub fn create_default() -> Result<PathBuf> {
        let config = Config::default();
        config.save()?;
        get_config_path()
    }
}

fn apply_recall_mode(content: &str, mode: crate::core::retriever::RecoveryMode) -> Result<String> {
    use crate::core::retriever::RecoveryMode;
    let mut doc: toml_edit::DocumentMut = content
        .parse()
        .map_err(|e| anyhow::anyhow!("config.toml is not valid TOML: {e}"))?;

    let legacy = doc.remove("tee");
    let retriever_is_table = doc
        .get("retriever")
        .is_some_and(|item| item.as_table_like().is_some());
    if !retriever_is_table {
        doc["retriever"] = toml_edit::Item::Table(toml_edit::Table::new());
    }
    let mode_str = match mode {
        RecoveryMode::Sqlite => "sqlite",
        RecoveryMode::Tee => "tee",
        RecoveryMode::Disabled => "disabled",
    };
    doc["retriever"]["mode"] = toml_edit::value(mode_str);

    if let Some(legacy) = legacy.as_ref().and_then(|i| i.as_table_like()) {
        let tee = LegacyTeeConfig {
            enabled: legacy

View on GitHub (pinned to 0924356b4c)