clockworklabs/SpacetimeDB · error · std::io::Error

workspace section missing

Error message

workspace section missing

What it means

Same CLI build-script path (crates/cli/build.rs:454): after confirming the root Cargo.toml is a table, extract_workspace_metadata requires a [workspace] section to read workspace.package.edition (defaulting to 2021) and workspace.dependencies versions for the embedded template metadata. A table-rooted manifest without [workspace] produces this InvalidData error, and the .expect() at build.rs:104 panics the build.

Source

Thrown at crates/cli/build.rs:454

            repo_root.display()
        )
    })
}

fn extract_workspace_metadata(path: &Path) -> io::Result<(String, BTreeMap<String, String>)> {
    let content = fs::read_to_string(path)?;
    let parsed: Value = content
        .parse()
        .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;

    let table = parsed
        .as_table()
        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "workspace manifest is not a table"))?;

    let workspace = table
        .get("workspace")
        .and_then(Value::as_table)
        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "workspace section missing"))?;

    let edition = workspace
        .get("package")
        .and_then(Value::as_table)
        .and_then(|pkg| pkg.get("edition"))
        .and_then(Value::as_str)
        .unwrap_or("2021")
        .to_string();

    let mut versions = BTreeMap::new();
    if let Some(deps) = workspace.get("dependencies").and_then(Value::as_table) {
        for (name, value) in deps {
            let version_opt = match value {
                Value::String(s) => Some(normalize_version(s)),
                Value::Table(table) => table.get("version").and_then(Value::as_str).map(normalize_version),
                _ => None,
            };

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Restore a [workspace] section in the root Cargo.toml with the crate members (e.g. [workspace] with members = ["crates/*"]).
  2. Recover the section from git history: `git show HEAD:Cargo.toml`.
  3. If the workspace root genuinely moved, restore the expected repo layout so crates/cli/build.rs finds the original root manifest.

Example fix

# before (root Cargo.toml)
[package]
name = "root"
version = "0.1.0"

# after
[workspace]
members = ["crates/*"]
Defensive patterns

Strategy: validation

Validate before calling

let parsed: toml::Value = std::fs::read_to_string("Cargo.toml")?.parse()?;
anyhow::ensure!(
    parsed.get("workspace").map(|w| w.is_table()).unwrap_or(false),
    "root Cargo.toml is missing its [workspace] section"
);

Try / catch

match extract_workspace_metadata(&workspace_cargo) {
    Ok(meta) => meta,
    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string().contains("workspace section") => {
        // restore [workspace] from git history, then rebuild
        return Err(anyhow!("{e}"));
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Building the `spacetime` CLI when the root Cargo.toml is valid table-rooted TOML but contains no [workspace] section - e.g. the root was converted to a plain package manifest, or [workspace] was dropped in a merge.

Common situations: Forks that restructure the repo (moving the workspace elsewhere) without leaving a root workspace manifest; automated dependency bots deleting sections they do not understand; a crate manifest copy-pasted over the root.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/9f7bc1075af233fe. Report an issue: GitHub.