jdx/mise · error · std::io::Error

(io::Error reconstructed from serialized kind/message when…

Error message

{message} (io::Error reconstructed from serialized kind/message when reading workspace state)

What it means

When reading serialized workspace state, a previously persisted I/O failure is reconstructed with io::Error::new(kind, message). The panic/error surfaces if the stored kind or message cannot be turned back into a valid io::Error, meaning the saved state was corrupted or produced by an incompatible version.

Solutions

  1. Delete the stale workspace state/cache file and rerun the task so it is regenerated
  2. Ensure the same mise version wrote and reads the state file
  3. Report corruption if it recurs; the state file should never be hand-edited
Defensive patterns

Strategy: validation

Validate before calling

// before reading state
if !state_path.exists() || metadata(&state_path)?.len() == 0 {
    fs::remove_file(&state_path).ok(); // force regeneration
}

Type guard

fn is_valid_kind(kind: &str) -> bool {
    matches!(kind, "NotFound" | "PermissionDenied" | "Other")
}

Prevention

When it happens

Trigger: Calling code that reads workspace state via WorkspaceErr::to_result() when the stored variant is Err(kind, message); occurs only if the persisted kind/message pair is invalid or the state file was hand-edited or written by a mismatched mise version.

Common situations: A stale or corrupted mise.lock/workspace cache file on disk; upgrading/downgrading mise so the serialized state format changed; partially written state files after a crash.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/35c6ab8bd8e26de5. Report an issue: GitHub.

Appendix: source

Thrown at src/task/workspace.rs:408

    }

    fn cache_key(&self, path: &Path) -> PathBuf {
        normalize_filesystem_path(path)
    }
}

impl<T: Clone> CachedIo<T> {
    fn from_result(result: io::Result<T>) -> Self {
        match result {
            Ok(value) => Self::Ok(value),
            Err(error) => Self::Err(error.kind(), error.to_string()),
        }
    }

    fn to_result(&self) -> io::Result<T> {
        match self {
            Self::Ok(value) => Ok(value.clone()),
            Self::Err(kind, message) => Err(io::Error::new(*kind, message.clone())),
        }
    }
}

fn normalize_filesystem_path(path: &Path) -> PathBuf {
    let mut normalized = PathBuf::new();
    for component in path.components() {
        match component {
            Component::CurDir => {}
            component => normalized.push(component.as_os_str()),
        }
    }
    if normalized.as_os_str().is_empty() && !path.as_os_str().is_empty() {
        normalized.push(".");
    }
    normalized
}

View on GitHub (pinned to 533346cc37)