transact-rs/sqlx · error

Invalid `cargo metadata` output

Error message

Invalid `cargo metadata` output

What it means

After `cargo metadata` runs, sqlx parses its stdout as JSON to extract `workspace_root`. This `.expect()` panics when `cargo metadata` produced output that is not valid JSON of the expected shape (e.g. the command emitted warnings/error text or an unexpected format version on stdout).

Source

Thrown at sqlx-macros-core/src/query/metadata.rs:53

            use serde::Deserialize;
            use std::process::Command;

            let cargo = crate::env("CARGO").unwrap();

            let output = Command::new(cargo)
                .args(["metadata", "--format-version=1", "--no-deps"])
                .current_dir(&self.manifest_dir)
                .env_remove("__CARGO_FIX_PLZ")
                .output()
                .expect("Could not fetch metadata");

            #[derive(Deserialize)]
            struct CargoMetadata {
                workspace_root: PathBuf,
            }

            let metadata: CargoMetadata =
                serde_json::from_slice(&output.stdout).expect("Invalid `cargo metadata` output");

            *root = Some(metadata.workspace_root);
        }
        root.clone().unwrap()
    }
}

pub fn try_for_crate() -> crate::Result<Arc<Metadata>> {
    /// The `MtimeCache` in this type covers the config itself,
    /// any changes to which will indirectly invalidate the loaded env vars as well.
    #[expect(clippy::type_complexity)]
    static METADATA: Mutex<
        HashMap<String, Arc<MtimeCache<Arc<Metadata>>>, BuildHasherDefault<DefaultHasher>>,
    > = Mutex::new(HashMap::with_hasher(BuildHasherDefault::new()));

    let manifest_dir = crate::env("CARGO_MANIFEST_DIR")?;

    let cache = METADATA

View on GitHub (pinned to 03af8bcc57)

Solutions

  1. Run `cargo metadata --format-version=1 --no-deps` manually and verify stdout is pure JSON.
  2. Remove cargo wrappers/aliases that add non-JSON output to stdout.
  3. Update or align the toolchain (rustup update) so cargo's metadata format matches expectations.
  4. Rebuild with `cargo clean` to rule out stale cached macro output.
Defensive patterns

Strategy: validation

Validate before calling

// Verify stdout parses as JSON before relying on macro builds:
let out = std::process::Command::new("cargo")
    .args(["metadata", "--format-version=1", "--no-deps"]).output().unwrap();
let v: serde_json::Value = serde_json::from_slice(&out.stdout)
    .expect("stdout is not valid JSON — check for cargo wrappers printing extra output");
assert!(v.get("workspace_root").is_some());

Prevention

When it happens

Trigger: Compiling with sqlx macros when `cargo metadata --format-version=1` stdout fails `serde_json::from_slice` — corrupted stderr/stdout mixing, custom cargo wrappers printing extra output, or a cargo version emitting an incompatible format.

Common situations: Wrapper scripts or cargo aliases that print banners to stdout; extremely old/new cargo with format drift; intercepted process output in unusual build environments.

Related errors


AI-assisted analysis of transact-rs/sqlx@03af8bcc57 (2026-09-03). Data as JSON: /api/errors/4c7fa26001a78f4f. Report an issue: GitHub.