jdx/mise · error
managed system path '{}' is declared as both a file and a di
Error message
managed system path '{}' is declared as both a file and a directory What it means
During planning of `[bootstrap.files]` / `[bootstrap.directories]`, a file entry's construction failed with a secret-unavailable error (its template references a secret whose env var/keychain value is missing, detected via secrets::is_unavailable downcasting to SecretUnavailable), AND the same normalized path is also declared under `[bootstrap.directories]`. Because the file couldn't be inspected, mise can't reconcile the file/directory overlap safely, so it bails instead of guessing (managed_files.rs:207-213).
Source
Thrown at src/system/managed_files.rs:209
) -> Result<(
Vec<ManagedFileRequest>,
Vec<ManagedDirectoryRequest>,
Vec<ResourcePlan>,
)> {
let mut files = vec![];
let mut unavailable = vec![];
let mut directories = directories_from_config(config)?;
let directory_states = directories
.iter()
.map(|directory| (directory.path.as_path(), directory.state))
.collect::<std::collections::HashMap<_, _>>();
for (path, (file, base)) in merged_files_from_config(config)? {
let state = file.state;
match ManagedFileRequest::from_toml(config, path.clone(), file, &base, secrets) {
Ok(file) => files.push(file),
Err(error) if super::secrets::is_unavailable(&error) => {
if directory_states.contains_key(path.as_path()) {
bail!(
"managed system path '{}' is declared as both a file and a directory",
path.display()
);
}
validate_present_ancestors(&path, state, &directory_states)?;
unavailable.push(ResourcePlan::new(
ResourceId::new("file", path.to_string_lossy().into_owned()),
"not inspected: required secret unavailable",
"template rendered",
ResourceAction::Unknown,
));
}
Err(error) => return Err(error),
}
}
ignore_non_linux_account_principals(config, &mut files, &mut directories);
validate_requests(&files, &directories)?;
inspect_paths(&mut files, &mut directories)?;View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Remove one of the two declarations for the same path — a path must be either a file or a directory, never both
- If you intended to migrate, delete the old `[bootstrap.files."<path>"]` block entirely and keep the directory entry (or the reverse)
- Provision the missing secret (set the env var / keychain entry) so the file request constructs normally — though the duplicate will then be caught by validate_requests anyway, so the declaration conflict must be fixed regardless
- Check every layered mise.toml (project, ~/.config/mise, MISE_CONFIG_FILE) for a stale duplicate
Example fix
# before
[bootstrap.files."/etc/myapp"]
content = "{{ secrets.token }}"
template = true
[bootstrap.directories."/etc/myapp"]
owner = "root"
# after
[bootstrap.directories."/etc/myapp"]
owner = "root" Defensive patterns
Strategy: validation
Validate before calling
# Validate before running bootstrap: no path in both tables (any layer), and secrets set for templated files
use std::collections::HashSet;
let dirs: HashSet<_> = layers().iter().flat_map(|c| c.bootstrap.directories.keys().map(normalize)).collect();
for c in layers() {
for path in c.bootstrap.files.keys() {
assert!(!dirs.contains(&normalize(path)), "path {path} declared as both file and directory");
}
}
for f in templated_files() { ensure_secret_available(f)?; } // fail loudly before planning Prevention
- Treat a path as having exactly one type across ALL config layers — enforce with a lint script in CI
- When migrating a path between files and directories, delete the old block in the same commit
- Provide required secret env vars (or keychain entries) before running bootstrap so the unavailable-secret branch is never taken
When it happens
Trigger: A mise.toml with both `[bootstrap.files."/etc/app"]` (templated, whose required secret env var is unset) and `[bootstrap.directories."/etc/app"]`. Normally the duplicate-path check at validate_requests (line 394) catches overlaps, but the secret-unavailable branch runs earlier during request construction, so it has its own copy of the conflict check before planning a 'not inspected' placeholder.
Common situations: Refactoring config and moving a path from files to directories (or vice versa) while the old block is left behind; templated file whose secret wasn't provisioned on a new machine, exposing the latent duplicate declaration; layered config files (project + ~/.config/mise) each declaring the same path in different tables.
Related errors
- managed file paths '{previous}' and '{path}' normalize to th
- managed directory paths '{previous}' and '{path}' normalize
- managed path '{}' cannot be present while managed ancestor '
- [bootstrap.files]."{}": source and content are mutually excl
- [bootstrap.files]."{}": present files require source or cont
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/87f62b4765280189.
Report an issue: GitHub.