unicity-aos/aos-ce · error

Capsule.toml is not valid TOML

Error message

Capsule.toml is not valid TOML: {e}

What it means

`validate_manifest` first tries to parse Capsule.toml into a TOML document; if parsing fails it stops immediately and returns a single Finding carrying the toml crate's error text. No other lints can run because there is no parse tree to inspect. This is a parse-time failure, not a semantic lint failure.

Solutions

  1. Read the toml error message appended to the Finding: it gives the line/column of the syntax error; fix that line.
  2. Validate the file with a TOML parser/linter (e.g. `taplo lint Capsule.toml`) before running the forge again.
  3. If generated programmatically, serialize with a TOML library instead of string concatenation.

Example fix

# before
capabilities = [uplink]

# after
capabilities = { uplink = [] }
# or use a [capabilities] table
Defensive patterns

Strategy: validation

Validate before calling

// Rust: pre-validate TOML before the linter
toml::from_str::<toml::Value>(&src).map_err(|e| format!("invalid TOML: {e}"))?;

Prevention

When it happens

Trigger: Calling `validate_manifest(toml_src)` with a string containing TOML syntax errors: unbalanced brackets, invalid key names, unterminated strings, wrong indentation in inline tables, or duplicate keys.

Common situations: Hand-editing Capsule.toml and dropping a bracket or quote, pasting YAML-style config, saving the wrong file, or an editor mangling UTF-8/special characters.

Related errors


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/5227edb7a88b2fc9. Report an issue: GitHub.

Appendix: source

Thrown at capsules/capsule-forge/src/checks.rs:63

    let parts: Vec<&str> = v.split('.').collect();
    parts.len() == 3
        && parts
            .iter()
            .all(|p| !p.is_empty() && p.bytes().all(|b| b.is_ascii_digit()))
}

/// A topic segment is malformed if the key has empty segments
/// (leading/trailing/consecutive dots).
fn has_empty_segments(topic: &str) -> bool {
    topic.is_empty() || topic.starts_with('.') || topic.ends_with('.') || topic.contains("..")
}

/// Run all manifest lints. Returns the findings in roughly severity order.
pub(crate) fn validate_manifest(toml_src: &str) -> Vec<Finding> {
    let root: Toml = match toml_src.parse() {
        Ok(t) => t,
        Err(e) => {
            return vec![Finding::err(
                format!("Capsule.toml is not valid TOML: {e}"),
                "Fix the syntax error reported above; the rest of the lint can't run until it parses.",
            )];
        }
    };

    let mut out = Vec::new();
    check_package(&root, &mut out);
    check_component(&root, &mut out);
    check_capabilities(&root, &mut out);
    check_env(&root, &mut out);
    let (pub_keys, sub_keys) = collect_topics(&root, &mut out);
    check_tool_bus(&sub_keys, &pub_keys, &root, &mut out);
    check_topic_shapes(&pub_keys, &sub_keys, &mut out);
    out
}

fn check_capabilities(root: &Toml, out: &mut Vec<Finding>) {

View on GitHub (pinned to f6f22024fb)