rust-lang/cargo · error

bin is an array of tables

Error message

bin is an array of tables

What it means

Invariant in `cargo new`'s manifest builder. When a binary source file is detected (not `src/main.rs`), the code does `manifest["bin"].or_insert(Item::ArrayOfTables(ArrayOfTables::new())).as_array_of_tables_mut().expect("bin is an array of tables")`. Because the value is either pre-existing as `ArrayOfTables` or just inserted as one, the downcast cannot fail — the panic guards a toml_edit shape assumption.

Source

Thrown at src/ops/cargo_new.rs:827

        array.push(registry);
        manifest["package"]["publish"] = toml_edit::value(array);
    }
    let dep_table = toml_edit::Table::default();
    manifest["dependencies"] = toml_edit::Item::Table(dep_table);

    // Calculate what `[lib]` and `[[bin]]`s we need to append to `Cargo.toml`.
    for i in &opts.source_files {
        if i.bin {
            if i.relative_path != "src/main.rs" {
                let mut bin = toml_edit::Table::new();
                bin["name"] = toml_edit::value(name);
                bin["path"] = toml_edit::value(i.relative_path.clone());
                manifest["bin"]
                    .or_insert(toml_edit::Item::ArrayOfTables(
                        toml_edit::ArrayOfTables::new(),
                    ))
                    .as_array_of_tables_mut()
                    .expect("bin is an array of tables")
                    .push(bin);
            }
        } else if i.relative_path != "src/lib.rs" {
            let mut lib = toml_edit::Table::new();
            lib["path"] = toml_edit::value(i.relative_path.clone());
            manifest["lib"] = toml_edit::Item::Table(lib);
        }
    }

    let manifest_path = paths::normalize_path(&path.join("Cargo.toml"));
    if let Ok(root_manifest_path) = find_root_manifest_for_wd(&manifest_path) {
        let root_manifest = paths::read(&root_manifest_path)?;
        // Sometimes the root manifest is not a valid manifest, so we only try to parse it if it is.
        // This should not block the creation of the new project. It is only a best effort to
        // inherit the workspace package keys.
        if let Ok(mut workspace_document) = root_manifest.parse::<toml_edit::DocumentMut>() {
            let display_path = get_display_path(&root_manifest_path, &path)?;
            let can_be_a_member = can_be_workspace_member(&display_path, &workspace_document)?;

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Report as a cargo bug if reproduced with stock `cargo new`.
  2. If using a custom cargo build, ensure any pre-existing `[bin]`/`bin` key in the manifest template is shaped as `[[bin]]` array-of-tables before this code runs.
  3. Validate the template with `toml_edit` and normalize `bin` to `ArrayOfTables` before entering the loop.

Example fix

// before
manifest["bin"]
    .or_insert(toml_edit::Item::ArrayOfTables(toml_edit::ArrayOfTables::new()))
    .as_array_of_tables_mut()
    .expect("bin is an array of tables")
    .push(bin);

// after (explicit shape check with a clear error)
let bins = match manifest.entry("bin").or_insert_with(||
    toml_edit::Item::ArrayOfTables(toml_edit::ArrayOfTables::new())) {
    toml_edit::Item::ArrayOfTables(t) => t,
    other => bail!("`bin` must be an array of tables, found {:?}", other.type_name()),
};
bins.push(bin);
Defensive patterns

Strategy: validation

Validate before calling

// If you generate Cargo.toml templates consumed by cargo new, validate shape first.
if let Some(bin) = manifest.get("bin") {
    assert!(matches!(bin, toml_edit::Item::ArrayOfTables(_)),
        "[bin] must be an array of tables, got {:?}", bin.type_name());
}

Prevention

When it happens

Trigger: Reachable only if `manifest["bin"]` already exists in the `Cargo.toml` template as a non-array-of-tables value (e.g. a user supplied a `bin = "string"` or `[bin]` table in a custom template), which would make `or_insert` a no-op and `as_array_of_tables_mut()` return `None`.

Common situations: Using `cargo new --bin` with a custom/patched cargo that pre-populates `manifest["bin"]` with the wrong shape; corrupt template injection in `cargo_new.rs::write_bare_version`/`MkOptions`. End users invoking standard `cargo new` cannot trigger it.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/11bd1ffc4feceabf.json. Report an issue: GitHub.