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

Missing "version" field in TypeScript bindings package.json

Error message

Missing "version" field in TypeScript bindings package.json

What it means

Raised by extract_ts_bindings_version in the CLI build script while compiling the `spacetime` CLI. The script reads crates/bindings-typescript/package.json to embed the TypeScript bindings version next to the workspace metadata used by `spacetime init` templates. If the parsed JSON has no top-level version field, or version is not a JSON string, it returns InvalidData with this message and the .expect() at build.rs:109 panics the build.

Source

Thrown at crates/cli/build.rs:491

            if let Some(version) = version_opt {
                versions.insert(name.clone(), version);
            }
        }
    }

    Ok((edition, versions))
}

fn extract_ts_bindings_version(path: &Path) -> io::Result<String> {
    let content = fs::read_to_string(path)?;
    let parsed: serde_json::Value =
        serde_json::from_str(&content).map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
    parsed
        .get("version")
        .and_then(serde_json::Value::as_str)
        .map(|s| s.to_string())
        .ok_or_else(|| {
            io::Error::new(
                io::ErrorKind::InvalidData,
                "Missing \"version\" field in TypeScript bindings package.json",
            )
        })
}

fn normalize_version(version: &str) -> String {
    version.trim().trim_start_matches('=').to_string()
}

fn write_if_changed(path: &Path, contents: &[u8]) -> io::Result<()> {
    match fs::read(path) {
        Ok(existing) if existing == contents => Ok(()),
        _ => {
            if let Some(parent) = path.parent() {
                fs::create_dir_all(parent)?;
            }
            let mut file = fs::File::create(path)?;

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Add a string "version" field to crates/bindings-typescript/package.json, e.g. "version": "1.0.0" consistent with the release.
  2. Restore the file from git history if it was mangled: `git checkout HEAD -- crates/bindings-typescript/package.json`.
  3. Fix the release/version-bump script so it always preserves the version field when rewriting package.json.

Example fix

// before (crates/bindings-typescript/package.json)
{
  "name": "bindings-typescript"
}

// after
{
  "name": "bindings-typescript",
  "version": "1.0.0"
}
Defensive patterns

Strategy: validation

Validate before calling

let pkg: serde_json::Value =
    serde_json::from_str(&std::fs::read_to_string("crates/bindings-typescript/package.json")?)?;
anyhow::ensure!(
    pkg.get("version").map(|v| v.is_string()).unwrap_or(false),
    "package.json must carry a string \"version\" field"
);

Try / catch

match extract_ts_bindings_version(&ts_bindings_package) {
    Ok(v) => v,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        // restore the file from git and rebuild: git checkout HEAD -- crates/bindings-typescript/package.json
        return Err(anyhow!("{e}"));
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Building the SpacetimeDB CLI when crates/bindings-typescript/package.json has had its "version" field removed or set to a non-string (number, object) - e.g. by release automation, a bad merge, or regenerating the file from a partial template.

Common situations: Version-bump scripts that rewrite package.json and drop fields; JSON merge conflicts resolved by hand; vendored copies where the file was regenerated without version.

Related errors


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