jdx/mise · error

unsupported encrypted file mode: {path}

Error message

unsupported encrypted file mode: {path}

What it means

encode() only supports git file modes 100644 (regular), 100755 (executable), and 120000 (symlink) for encrypted files. Any other mode string — directories, submodules, setuid bits, or malformed mode values — is rejected before building the plaintext envelope.

Source

Thrown at src/system/history/sync/files.rs:342

        })
        .collect::<Result<Vec<_>>>()?;
    encrypt(repo, path, object, &scheme, &recipients)
}

/// Encrypt bytes before they enter Git. Callers may store only the returned
/// envelope, never the input or the decrypted payload in repository objects.
pub(crate) fn encode(
    path: &str,
    mode: &str,
    content: &[u8],
    scheme: &str,
    recipients: &[Box<dyn age::Recipient + Send>],
) -> Result<Vec<u8>> {
    if control_file(path) {
        bail!("encrypt an external dotfile source instead of configuration: {path}");
    }
    if !matches!(mode, "100644" | "100755" | "120000") {
        bail!("unsupported encrypted file mode: {path}");
    }
    let inner = Plaintext {
        path: path.into(),
        mode: mode.into(),
        scheme: scheme.into(),
        content: Bytes(content.to_vec()),
    };
    let bytes = rmp_serde::to_vec_named(&inner)?;
    let outer = Envelope {
        path: path.into(),
        mode: mode.into(),
        scheme: scheme.into(),
        ciphertext: Bytes(agecrypt::encrypt_bytes(&bytes, recipients)?),
    };
    let mut encoded = MAGIC.to_vec();
    encoded.extend(rmp_serde::to_vec_named(&outer)?);
    if encoded.len() as u64 > agecrypt::MAX_ENCRYPTED_BYTES {
        bail!("encrypted file exceeds the size limit: {path}");

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Encrypt individual regular files (or symlinks) instead of directories or submodules.
  2. Normalize the file's permissions to 0644 or 0755 before syncing.
  3. Fix the mode value in the source config to a supported git mode.

Example fix

// before
encrypt_file(path, "160000", content, scheme, recipients)
// after
encrypt_file(path, "100644", content, scheme, recipients)
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED: [&str; 3] = ["100644", "100755", "120000"];
if !SUPPORTED.contains(&mode) {
    return Err(anyhow!("unsupported mode {mode} for {path}"));
}

Try / catch

match encrypt(path, mode, content, scheme, recipients) {
    Ok(bytes) => Ok(bytes),
    Err(e) if e.to_string().contains("unsupported encrypted file mode") => {
        eprintln!("skipping {path}: not a regular file/symlink");
        Ok(())
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling encrypt()/encode() with a mode string other than "100644" | "100755" | "120000" (e.g. "040755" for a directory, "160000" for a submodule, or an arbitrary string).

Common situations: Trying to encrypt a directory or git submodule; filesystems reporting unusual permission bits; a config that lets users set a mode manually and contains a typo.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/62a2b82db8d00af1. Report an issue: GitHub.