You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A --vars JSON file containing a duplicate key silently keeps the last value, with no warning:
{"x": 1, "x": 2}
compiles with x = 2. The user gets no signal that they wrote the same key twice.
This is the same class of bug as #200 (duplicate --set keys silently last-win), but a different mechanism — which is why it needs its own issue rather than riding along on the #200 fix.
Mechanism
mds build --vars f.json resolves through:
crates/mds-cli/src/build.rs:515-520 — load_optional_vars_file delegates to mds::load_vars_file.
crates/mds-core/src/lib.rs:1406 — load_vars_file reads the file (after the PF-004 symlink guard and the MAX_FILE_SIZE check).
Step 3 is where the duplicate disappears. serde_json's map deserializer inserts each key as it is parsed, so a repeated key overwrites the earlier entry. This is serde_json behaving as designed — JSON itself does not forbid duplicate object names — not a bug in the dependency.
#200 is a CLI-side problem with a CLI-side fix: --set arrives as set_vars: Vec<(String, String)>, so crates/mds-cli/src/build.rs:549-553 can inspect the vector for repeats before inserting into the HashMap. The duplicate is still visible at that point.
Here it is not. By the time load_vars_file returns HashMap<String, Value>, the duplicate has already been collapsed inside serde_json — there is nothing left for the CLI to detect. Catching it requires a duplicate-detecting deserializer in mds-core: a custom Visitor / MapAccess implementation that tracks seen keys during parsing and errors or warns on a repeat, replacing the plain serde_json::Value deserialization at lib.rs:1429.
Hard error is defensible for a file (unlike repeated CLI flags, a duplicate key in a checked-in JSON file is almost certainly a mistake, and JSON producers rarely emit them intentionally).
These should probably be decided together with #200 so --set and --vars do not end up with divergent behaviour for the same user error.
Blast radius
load_vars_file is pub in mds-core, a published crate, so changing its behaviour is a public-API change. Note that in-repo the only caller is the CLI (build.rs:518) — the napi, WASM, and Python binding crates do not call it — so the in-tree blast radius is small even though the API is public.
Why deferred
Found during design work on #200 and deliberately scoped out of it. #200's fix is a contained CLI-side check; this one requires a core-level deserializer change plus its own warn-vs-error decision, and bundling them would have widened that change materially.
A
--varsJSON file containing a duplicate key silently keeps the last value, with no warning:{"x": 1, "x": 2}compiles with
x = 2. The user gets no signal that they wrote the same key twice.This is the same class of bug as #200 (duplicate
--setkeys silently last-win), but a different mechanism — which is why it needs its own issue rather than riding along on the #200 fix.Mechanism
mds build --vars f.jsonresolves through:crates/mds-cli/src/build.rs:515-520—load_optional_vars_filedelegates tomds::load_vars_file.crates/mds-core/src/lib.rs:1406—load_vars_filereads the file (after the PF-004 symlink guard and theMAX_FILE_SIZEcheck).crates/mds-core/src/lib.rs:1429—serde_json::from_str::<serde_json::Value>(&content).Step 3 is where the duplicate disappears.
serde_json's map deserializer inserts each key as it is parsed, so a repeated key overwrites the earlier entry. This isserde_jsonbehaving as designed — JSON itself does not forbid duplicate object names — not a bug in the dependency.Why this is not fixable the way #200 is
#200 is a CLI-side problem with a CLI-side fix:
--setarrives asset_vars: Vec<(String, String)>, socrates/mds-cli/src/build.rs:549-553can inspect the vector for repeats before inserting into theHashMap. The duplicate is still visible at that point.Here it is not. By the time
load_vars_filereturnsHashMap<String, Value>, the duplicate has already been collapsed insideserde_json— there is nothing left for the CLI to detect. Catching it requires a duplicate-detecting deserializer inmds-core: a customVisitor/MapAccessimplementation that tracks seen keys during parsing and errors or warns on a repeat, replacing the plainserde_json::Valuedeserialization atlib.rs:1429.Open design question
Warn, or hard error?
--set, keeping the two surfaces consistent.These should probably be decided together with #200 so
--setand--varsdo not end up with divergent behaviour for the same user error.Blast radius
load_vars_fileispubinmds-core, a published crate, so changing its behaviour is a public-API change. Note that in-repo the only caller is the CLI (build.rs:518) — the napi, WASM, and Python binding crates do not call it — so the in-tree blast radius is small even though the API is public.Why deferred
Found during design work on #200 and deliberately scoped out of it. #200's fix is a contained CLI-side check; this one requires a core-level deserializer change plus its own warn-vs-error decision, and bundling them would have widened that change materially.
Cross-reference: #200.