jdx/mise · error
cannot retain an unreadable plaintext version of newly…
Error message
cannot retain an unreadable plaintext version of newly encrypted {} What it means
When a checkpoint omits certain files but tries to retain them in a readable form, retain_omitted validates each omitted entry against the recorded policy. If the policy marks the file as encrypted but the stored blob is not actually in the mise-encrypted-file-v1 format, keeping a plaintext copy of a newly encrypted file would defeat the encryption, so it bails. This is a safety invariant: encryption must be retroactive for the file, never leave readable plaintext.
Solutions
- Re-capture or re-checkpoint the file so it is stored in the encrypted format under the current policy
- Verify history.encryption recipients are configured and the encryption layer actually rewrote the file's blob (check it starts with mise-encrypted-file-v1)
- Exclude the path from the checkpoint omission list until its encrypted version exists, or temporarily remove the file from encryption policy to complete the transition consistently
Example fix
# before: policy says encrypt, but the blob is still plaintext [history.encryption] recipients = ["age1..."] # after: re-run the checkpoint after the encryption migration so the # stored object begins with 'mise-encrypted-file-v1\n', then omit safely
Defensive patterns
Strategy: validation
Validate before calling
# before relying on omission, confirm stored blobs are encrypted mise history verify 2>/dev/null || \ grep -q 'mise-encrypted-file-v1' <(mise history cat <path>) || \ echo "path still stored as plaintext; re-encrypt before omitting"
Prevention
- Complete encryption migrations in one step, then re-checkpoint affected files
- Never leave the encryption policy half-applied across captures
- Verify blob headers after changing recipients
When it happens
Trigger: Running a checkpoint/attempt_locked flow where a file is newly covered by [history] encryption policy, the omission list references that file, and its blob content does not start with the mise-encrypted-file-v1 header.
Common situations: Adding encryption recipients to history.encryption while files were previously captured in plaintext; a partial encryption migration where the policy says encrypt but the object store still holds the plaintext version.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- an operation record always has an operation
- appeared after was protected; nothing more was changed
- changed after it was protected; nothing more was changed
- checked by the caller
- checkpoint did not finish; there is no state to roll back to
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/7ee9d477af3145b5.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/checkpoint.rs:926
.flat_map(|path| path.ancestors().skip(1))
.collect();
for file in repo.ls_tree(parent)? {
let located = roots.locate(&file.path);
let Some(path) = located.path() else { continue };
if !omitted.iter().any(|omitted| path.starts_with(omitted))
|| !tracked.would_retain(path)?
|| repo.object_at(tree, &file.path)?.is_some()
{
continue;
}
let Some(entry) = tracked.entry_for(path) else {
continue;
};
if entry.tree_path(path)? != file.path {
continue;
}
if entry.policy.encrypt && !repo.blob_starts_with(&file.oid, b"mise-encrypted-file-v1\n")? {
eyre::bail!(
"cannot retain an unreadable plaintext version of newly encrypted {}",
display_path(path)
);
}
let display = display_path(path);
modes.remove(&display);
if let Some(mode) = record.tree.modes.get(&display) {
modes.insert(display, *mode);
}
for parent in path
.ancestors()
.skip(1)
.take_while(|parent| parent.starts_with(&entry.path))
{
if !observed_directories.contains(parent) {
let display = display_path(parent);
if let Some(mode) = record.tree.modes.get(&display) {
modes.insert(display, *mode);View on GitHub (pinned to 533346cc37)