TensorFlow.js weightsManifest duplicate weight names — silent last-write-wins
Overview
This repository demonstrates a model weight integrity issue in TensorFlow.js
layers-model format: a model.json can contain the same logical weight name in
multiple weightsManifest groups with different binary values. @tensorflow/tfjs
v4.22.0 loadLayersModel accepts this artifact, loads all groups sequentially,
and silently resolves the duplicate by last-write-wins — the later group's value
becomes the effective runtime weight with no warning emitted.
The PoC declares dense/kernel = 1.0 in Group[0] and dense/kernel = 999.0 in
Group[1]. The runtime resolves the duplicate and produces predict([[1.0]]) = 999.0.
Differential
dense/kernel |
predict([[1.0]]) |
Warning | |
|---|---|---|---|
| Group[0] first-declared value | 1.0 | 1.0 | — |
@tensorflow/tfjs v4.22.0 effective value |
999.0 | 999.0 | None |
Requirements
- Node.js >= 14
@tensorflow/tfjs^4.22.0
npm install
Reproduction Steps
# Step 1: Generate the crafted model
node create_model.js .
# Step 2: Inspect declared duplicate weight values
node inspect_model.js .
# Step 3: Run the runtime differential (loads all groups — last-write-wins)
node reproduce.js .
Or all steps at once:
npm run poc
Expected Output
inspect_model.js (declared values across all groups):
DECLARED_GROUP0_KERNEL=1
DECLARED_GROUP1_KERNEL=999
DUPLICATE_WEIGHT_NAME=dense/kernel
reproduce.js (@tensorflow/tfjs v4.22.0 effective value after last-write-wins):
RUNTIME_KERNEL=999
RUNTIME_OUTPUT=999
OUTPUT_FLIP_CONFIRMED=true
WEIGHT_WARNING_EMITTED=false
Format Details
model.json in the TF.js layers-model format contains a weightsManifest array.
Each element is a group with paths (binary shard files) and weights (weight
name/shape/dtype specs). The original design supports sharding: splitting a
large weight set across multiple .bin files for parallel HTTP loading.
The crafted model uses this structure with two groups declaring the same weight names:
"weightsManifest": [
{
"paths": ["group0-shard1of1.bin"],
"weights": [
{ "name": "dense/kernel", "shape": [1, 1], "dtype": "float32" },
{ "name": "dense/bias", "shape": [1], "dtype": "float32" }
]
},
{
"paths": ["group1-shard1of1.bin"],
"weights": [
{ "name": "dense/kernel", "shape": [1, 1], "dtype": "float32" },
{ "name": "dense/bias", "shape": [1], "dtype": "float32" }
]
}
]
group0-shard1of1.bin:dense/kernel = 1.0(first-declared value)group1-shard1of1.bin:dense/kernel = 999.0(effective runtime value after last-write-wins)
Files
| File | Description |
|---|---|
model_crafted.json |
Model with duplicate dense/kernel across two weightsManifest groups |
group0-shard1of1.bin |
Group[0] binary: dense/kernel=1.0 |
group1-shard1of1.bin |
Group[1] binary: dense/kernel=999.0 |
create_model.js |
Generates the crafted model and shards |
inspect_model.js |
Reports duplicate weight declarations across weightsManifest groups |
reproduce.js |
Runs @tensorflow/tfjs and confirms effective value is 999.0 |
expected_output.txt |
Expected output values |
SHA256SUMS_T1.txt |
File integrity checksums |