jdx/mise · error
cannot save
Error message
cannot save: {reason} What it means
Before performing a save, capture checks `store.unavailable()` and aborts if the history store cannot be used (e.g. the store directory is unreadable, corrupt, or in an incompatible state). The reason string from the store is embedded in the error.
Solutions
- Read the reason embedded in the error message for the specific cause
- Verify the history state directory exists and is writable
- Repair or reset the store per the reason (re-initialize, fix permissions, free disk space)
Example fix
// before mise dot save // cannot save: store directory not writable // after chmod u+w ~/.local/share/mise/dotfiles-history mise dot save
Defensive patterns
Strategy: try-catch
Validate before calling
store_dir=~/.local/share/mise/dotfiles-history [ -d "$store_dir" ] && [ -w "$store_dir" ] || echo "store dir missing or unwritable"
Try / catch
mise dot save update || {
status=$?
echo "save failed (store unavailable?) — see message for reason"
exit $status
} Prevention
- Keep the history state directory writable by the current user
- Monitor disk space on the state partition
- Avoid running concurrent mise dot mutations
- After mise upgrades, verify the store still opens (mise dot status)
When it happens
Trigger: Running `mise dot save` when the history store reports itself unavailable via Store::unavailable(), evaluated at the start of capture().
Common situations: Corrupt or version-mismatched history store directory; unwritable/read-only state dir; store locked by an incompatible writer; disk full.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- cannot synchronize
- a glob is required
- `--all` needs `--to
- at least one target or --changed is required
- cannot apply
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/327832601efcfe6a.
Report an issue: GitHub.
Appendix: source
Thrown at src/cli/dotfiles/save.rs:127
draft.description = self.description.clone();
draft.description_source = Some(if trigger == Trigger::Agent {
DescriptionSource::Agent
} else {
DescriptionSource::User
});
draft.task = self.task.clone();
draft.labels = self.label.clone();
tokio::task::spawn_blocking(move || self.save_checkpoint(&store, &tracked, draft)).await?
}
fn capture(
&self,
store: &Store,
tracked: &crate::system::history::tracked::TrackedSet,
draft: Draft,
) -> Result<()> {
if let Some(reason) = store.unavailable() {
bail!("cannot save: {reason}");
}
// a save is a write: it waits for no running operation, refuses to
// interleave with one, and closes one that died
let _operation = crate::system::history::scope::take_operation_lock(store, tracked)?;
match store.attempt(tracked, draft)? {
Outcome::Created(entry) => {
info!(
"history: saved checkpoint {}: {}",
entry.id, entry.checkpoint.description
);
Ok(())
}
Outcome::Unchanged => {
info!("history: nothing changed since the latest checkpoint");
Ok(())
}
Outcome::Unavailable(reason) => bail!("cannot save: {reason}"),
}View on GitHub (pinned to 533346cc37)