diem/diem · error
must be non-deletion
Error message
must be non-deletion
What it means
After a successful sandbox (non-VM) publish, the code is written via a ChangeSet. Modules are extracted with changeset.into_modules(), yielding (ModuleId, Option<Vec<u8>>) where the Option is Some for published/updated modules and None for deletions. Publish only produces additions, so the code expects(blob).expect("must be non-deletion") panics with 'must be non-deletion' if a deletion (None) unexpectedly appears — indicating an internal inconsistency (a module being republished/replaced resulted in a deletion entry).
Source
Thrown at language/tools/move-cli/src/sandbox/commands/publish.rs:151
has_error = true;
}
}
}
}
}
if !has_error {
let (changeset, events) = session.finish().map_err(|e| e.into_vm_status())?;
assert!(events.is_empty());
if verbose {
explain_publish_changeset(&changeset, state);
}
let modules: Vec<_> = changeset
.into_modules()
.map(|(module_id, blob_opt)| {
let addr_name = id_to_ident[&module_id];
let ident = (module_id, addr_name);
(ident, blob_opt.expect("must be non-deletion"))
})
.collect();
state.save_modules(&modules, named_address_mapping)?;
}
} else {
// NOTE: the VM enforces the most strict way of module republishing and does not allow
// backward incompatible changes, as as result, if this flag is set, we skip the VM process
// and force the CLI to override the on-disk state directly
let mut serialized_modules = vec![];
for ((_, address_name_opt), module) in modules {
let id = module.self_id();
let mut module_bytes = vec![];
module.serialize(&mut module_bytes)?;
serialized_modules.push(((id, address_name_opt), module_bytes));
}
state.save_modules(&serialized_modules, named_address_mapping)?;
}
View on GitHub (pinned to fc4714a8ea)
Solutions
- Avoid republishing the same module at the same address; bump the package version or move to a new module/address.
- Clear the affected module (or reset storage/) and republish cleanly from source.
- Ensure you consistently use one publish path (sandbox publish vs VM) for a given storage directory.
- If reproducible, report it — this is an invariant violation (expect) rather than a normal user-facing error path.
Example fix
// before: republish over existing module triggers deletion entry panic $ move sandbox publish build/my_pkg # module 0x42::app already in storage must be non-deletion // after: remove stale storage first $ rm -rf storage && move sandbox publish build/my_pkg
Defensive patterns
Strategy: fallback
Validate before calling
// Detect existing modules at the same addresses before a lenient republish
for m in built_modules {
if state.get_module(&m.id).is_some() {
warn("module {} already published; reset storage or bump version", m.id);
}
} Prevention
- Don't republish identical module addresses into the same storage
- Use a fresh storage dir per publish iteration
- Stick to one publish path (sandbox vs VM) per storage directory
When it happens
Trigger: Publishing over existing state where the sandbox changeset records a module deletion instead of an upsert — e.g. republishing a module under conditions the CLI's lenient republish path handles via changesets, and the changeset marks the old module for deletion.
Common situations: Republishing a module that already exists at the same address; state left in an inconsistent condition by earlier partial publishes; mixing publish modes (VM vs sandbox) on the same storage.
Related errors
- Invalid module name in publish ordering: {}
- No modules to publish
- Deleting a module is not supported
- [EpochManager] Same epoch should not come to process_differe
- The transaction at version {} got the status of 'Retry'
AI-assisted analysis of diem/diem@fc4714a8ea (2026-09-04).
Data as JSON: /api/errors/68bf8806f0f97dd0.
Report an issue: GitHub.