jdx/mise · critical
cannot publish: encrypted path {} has an unencrypted or inva
Error message
cannot publish: encrypted path {} has an unencrypted or invalid version in commit {commit}; encrypting the latest version does not erase earlier plaintext. Review and explicitly rewrite or replace that history before connecting it to origin; mise will not rewrite it automatically What it means
audit_history verifies that every commit touching an encrypted path contains a validly encrypted version of that path (age-envelope with a recognized mode and the age header). If any historical version of the path is unencrypted or malformed, publishing is refused: encrypting the latest version would not erase plaintext from earlier commits, and mise will not rewrite history automatically.
Source
Thrown at src/system/history/sync/files.rs:131
if !protected.iter().any(|path| {
entry.path == *path
|| entry
.path
.strip_prefix(path)
.is_some_and(|rest| rest.starts_with('/'))
}) || !checked.insert((entry.path.clone(), entry.mode.clone(), entry.oid.clone()))
{
continue;
}
let object = (entry.mode, entry.oid);
let valid =
envelope(repo, &object, agecrypt::MAX_ENCRYPTED_BYTES)?.is_some_and(|outer| {
outer.path == entry.path
&& matches!(outer.mode.as_str(), "100644" | "100755" | "120000")
&& outer.ciphertext.0.starts_with(b"age-encryption.org/v1\n")
});
if !valid {
bail!(
"cannot publish: encrypted path {} has an unencrypted or invalid version in commit {commit}; encrypting the latest version does not erase earlier plaintext. Review and explicitly rewrite or replace that history before connecting it to origin; mise will not rewrite it automatically",
entry.path
);
}
}
}
if let Ok(mut cache) = AUDITS.lock() {
// One watcher normally uses one repository. Bound temporary onboarding
// probes without adding another durable history or state file.
if cache.len() >= 64 && !cache.contains_key(repo.dir()) {
cache.pop_first();
}
cache.insert(
repo.dir().to_path_buf(),
VerifiedAncestry {
head: head.into(),
protected,
},View on GitHub (pinned to afd2eddd3a)
Solutions
- Rewrite history to encrypt or purge the plaintext versions (e.g. `git filter-repo` or an interactive rebase re-committing the file encrypted), then re-run publish.
- Alternatively start a fresh history: replace the repo/ref and push the newly encrypted baseline.
- Inspect `git log --follow -- <path>` in the history repo to locate the offending commit and version before rewriting.
Example fix
// before # plaintext config committed in history, encryption enabled later // after git filter-repo --path secrets.env --invert-paths # or re-commit encrypted across history mise pull # audit now passes
Defensive patterns
Strategy: validation
Validate before calling
# before publishing, check every historical version of the path is encrypted
git log --format=%H -- path/to/secrets.env |
while read c; do git show "$c":path/to/secrets.env |
head -c 22 | grep -q 'age-encryption.org/v1' || echo "plaintext in $c"; done Try / catch
if let Err(e) = publish() {
if e.to_string().starts_with("cannot publish: encrypted path") {
// rewrite history (git filter-repo / rebase) before retrying
}
} Prevention
- Enable encryption before first commit of sensitive paths
- Never commit plaintext versions of paths later marked encrypted
- Verify blobs start with the age header when importing history
When it happens
Trigger: Connecting a setup-history repo to origin where an encrypted path had a plaintext (or corrupt/non-age) blob in any commit in its history; encryption enabled after the path was already tracked unencrypted.
Common situations: User enables encryption on an existing history repo; a commit snuck in with a raw config before the encrypt step; the ciphertext blob is truncated or not age-formatted.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- cannot retain an unreadable plaintext version of newly encry
- trust the configuration before using its encryption recipien
- rustc produced no cacheable outputs
- rustc output is not a regular file: {}
- cache agent returned an unexpected publish response
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/a977735d92c03173.
Report an issue: GitHub.