Repository navigation
Description
Summary
In src/schemas/json/cargo.json, definitions.DetailedDependency asserts minProperties: 1 and nothing else. Cargo requires a dependency to carry a source — one of version, path, git or workspace. A dependency that has properties but no source satisfies the schema and is rejected by cargo.
Minimal reproduction
Given Cargo.toml:
[package]
name = "probe"
version = "0.1.0"
edition = "2021"
[dependencies]
serde = { features = ["derive"] }Against the published schema:
$ python -m check_jsonschema --schemafile cargo.json Cargo.toml
ok -- validation done
Against cargo (1.97.1):
$ cargo metadata --no-deps --format-version 1
error: failed to parse manifest at `.../Cargo.toml`
Caused by:
dependency (serde) specified without providing a local path, Git repository, version, or workspace dependency to use
Where the constraint stops one step short
minProperties: 1 is satisfied by any single property, and features, optional, default-features, branch, tag, rev, package and the rest are all properties. So {features = ["derive"]} validates.
The four things cargo accepts as a source, taken from its own error message above, each work on their own:
| declared | schema | cargo |
|---|---|---|
{version = "1"} |
ok | ok |
{path = "./sub"} |
ok | ok |
{git = "https://github.com/a/b"} |
ok | ok |
{features = ["derive"]} |
ok | rejected |
{branch = "main"} |
ok | rejected |
{optional = true} |
ok | rejected |
{default-features = false} |
ok | rejected |
I checked workspace = true, registry = "custom" and registry-index = "..." on their own as well; all three are rejected by cargo in a manifest with no [workspace], and workspace is named as a valid source in the error text, so I did not treat those three rows as evidence either way.
Why this is worth fixing
Forgetting the version while keeping something else is a common edit — you add features, lose version, and the editor stays quiet until cargo build. That is the case the schema is best placed to catch, since the editor is where the mistake is made.
Suggested fix
minProperties: 1 becomes redundant once the sources are expressed:
"anyOf": [
{"required": ["version"]},
{"required": ["path"]},
{"required": ["git"]},
{"required": ["workspace"]}
]anyOf and required are both fine in draft-07, which this file declares.
How it came up
I wrote a small mutation tester for validators — it mutates inputs a checker accepts and reports which mutations still get through. Run against this schema, it deleted the source from a dependency that validated and the schema still said ok. The tool is https://github.com/simin-yuan/greencheck (MIT, no dependencies); the reproduction above stands on its own without it.
Activity
simin-yuan commentedon Sep 25, 2026
Follow-up: the report above quoted cargo output. I have now re-run the whole reproduction against the real toolchain on this machine (cargo is installed here but not on PATH, which is why an earlier check wrongly concluded it was unavailable). Doing it for real changed one thing I suggested, so I am correcting that below.
Environment: cargo 1.97.1 (c980f4866 2026-06-30), rustc 1.97.1 (8bab26f4f 2026-07-14); check-jsonschema 0.38.0; schema as published at https://www.schemastore.org/cargo.json, which declares draft-07.
Each row is one package with a src/lib.rs and a single
[dependencies]entry, run throughcargo metadata --no-deps --format-version 1and throughcheck-jsonschema --schemafile cargo.json Cargo.toml.serde = { version = "1" }serde = { version = "1", features = ["derive"] }regex = { git = "https://github.com/rust-lang/regex.git" }regex = { git = "...", version = "1" }regex = { path = "../regex", version = "1" }serde = { features = ["derive"] }serde = { branch = "main" }serde = { optional = true }serde = { default-features = false }serde = { registry = "custom" }serde = { registry-index = "https://example.com/index" }regex = { git = "...", path = "../regex" }For the first rejected group cargo says exactly what the report quotes:
dependency (serde) specified without providing a local path, Git repository, version, or workspace dependency to useThe last row is refused for a different reason:
dependency (regex) specification is ambiguous. Only one of git or path is allowed.Correction. The
anyOfI proposed still accepts{ git = "...", path = "../regex" }, which cargo refuses, so it closes only half the gap. Both halves are needed: at least one source, and at most one ofgit/path:With those in place
minProperties: 1has nothing left to do. I have not tested this against the repository test files, and I did not look at the other placesDetailedDependencyis referenced, so treat it as a starting point rather than a ready patch.One measurement I would rather state than leave implied: inside a real
[workspace]whose root declaresworkspace.dependencies.serde, the entryserde = { workspace = true }parses, and so do variants that addversion,features,optionalordefault-features. The earlier row callingworkspace = truerejected was only ever about a manifest with no workspace, which the report flagged at the time. I am reporting what I measured, not claiming which combinations are normative.Also worth noting:
registryandregistry-indexon their own are not sources. Cargo rejects them with the same message asfeatures, and that message names only path, git, version and workspace.