jdx/mise · error
new config Arc is uniquely owned
Error message
new config Arc is uniquely owned
What it means
mise panics with 'new config Arc is uniquely owned' when `Arc::get_mut(&mut config)` returns `None` in `with_bootstrap_dry_run_config_files`. The function builds a fresh config `Arc` via `from_dir`-style re-parse and then mutates it in place (`vars`, `tera_ctx`, bootstrap config maps). This is only legal while the new Arc has refcount 1; if anything else cloned the Arc, the mutation is impossible and the invariant is broken.
Source
Thrown at src/config/mod.rs:486
) -> Result<Arc<Self>> {
let mut config = self.with_config_files(config_files);
let bootstrap_roots = self
.bootstrap_config_maps
.iter()
.filter_map(|map| map.config_root.as_deref())
.collect_vec();
let mut main_config_files = config.config_files.clone();
main_config_files
.retain(|path, _| !bootstrap_roots.iter().any(|root| path.starts_with(root)));
let vars = bootstrap_dry_run_vars(
Some(&self.config_files),
self.vars_results_cached(),
&main_config_files,
IndexMap::new(),
false,
)?;
let main_vars_changed = vars != self.vars;
let config_mut = Arc::get_mut(&mut config).expect("new config Arc is uniquely owned");
config_mut.vars = vars.clone();
config_mut.tera_ctx.insert("vars", &vars);
for map in &mut config_mut.bootstrap_config_maps {
let original_config_files = map.config_files.clone();
for (path, simulated) in &config_mut.config_files {
let belongs_to_map = match &map.config_root {
Some(root) => path.starts_with(root),
None => !bootstrap_roots.iter().any(|root| path.starts_with(root)),
};
if belongs_to_map {
insert_bootstrap_dry_run_config_file(
&mut map.config_files,
path.clone(),
simulated.clone(),
);
}
}
if map.config_root.is_some() {View on GitHub (pinned to afd2eddd3a)
Solutions
- Ensure the config Arc returned by the parse step is not cloned or stored anywhere before `Arc::get_mut` runs
- If shared ownership is genuinely needed, wrap the mutated fields in `Arc::make_mut`/`RwLock` instead of relying on uniqueness
- Re-run the dry-run config build so a brand-new Arc is produced immediately before mutation
- Add a debug assertion or log near the parse call to catch accidental clones in development
Example fix
// before
let config = self.reparse_for_dry_run(&files)?;
let shared = config.clone(); // leaks a reference
let config_mut = Arc::get_mut(&mut config).expect("new config Arc is uniquely owned");
// after
let config = self.reparse_for_dry_run(&files)?;
// no clones before mutation
let config_mut = Arc::get_mut(&mut config).expect("new config Arc is uniquely owned"); Defensive patterns
Strategy: validation
Validate before calling
assert_eq!(Arc::strong_count(&config), 1, "config Arc must be uniquely owned before mutation");
Prevention
- Do not clone the freshly built config Arc before the dry-run mutation block
- Prefer Arc::make_mut when shared ownership is possible
- Keep the parse and mutate steps adjacent with no intermediate storage
When it happens
Trigger: Calling `with_bootstrap_dry_run_config_files` when the freshly parsed config `Arc` was shared/cloned before reaching `Arc::get_mut` — e.g. a refactor stashes a clone of the new config (in a cache, guard, or closure) before the mutation block, or the config construction path returns an Arc that aliases an existing cached config.
Common situations: A developer introduces caching of the newly built config or holds a clone across the re-parse call; concurrent access to the config while the dry-run variant mutates it; changes to the config-load path that return a shared singleton instead of a fresh Arc.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- explicit task name was just found
- declaring bootstrap config is loaded
- configured notifications came from managed files
- configured notifications prepared services
- system files were preflighted when not skipped
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/c3f0d35822e71087.
Report an issue: GitHub.