jdx/mise · error
could not get mtime for watch file: {}
Error message
could not get mtime for watch file: {} What it means
After confirming a watched file exists, mise tries to read its mtime to compare against the cached value. If get_file_mtime returns None despite path.exists() being true, mise cannot validate the cache entry and bails rather than trusting unverified cached env.
Source
Thrown at src/toolset/env_cache.rs:81
for (path, expected_mtime) in watch_files.iter().zip(expected_mtimes.iter()) {
if !path.exists() {
// mtime=0 means file didn't exist when cached - skip if still doesn't exist
if *expected_mtime == 0 {
continue;
}
bail!("watch file no longer exists: {}", path.display());
}
if let Some(current_mtime) = get_file_mtime(path) {
if current_mtime != *expected_mtime {
bail!(
"watch file mtime changed: {} (expected: {}, current: {})",
path.display(),
expected_mtime,
current_mtime
);
}
} else {
bail!("could not get mtime for watch file: {}", path.display());
}
}
Ok(())
}
/// Represents the cached environment data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct CachedEnv {
/// Cached environment variables
pub env: BTreeMap<String, String>,
/// Variables explicitly removed by env directives
#[serde(default)]
pub env_remove: BTreeSet<String>,
/// User-configured paths from env._.path directives
pub user_paths: Vec<PathBuf>,
/// Tool paths from installations
pub tool_paths: Vec<PathBuf>,
/// Time when the cache was createdView on GitHub (pinned to afd2eddd3a)
Solutions
- Re-run the command — the transient race usually resolves and the cache is rebuilt
- Check filesystem permissions allowing stat on the watched files
- Ensure no other process deletes/replaces the watched config files while mise runs
- Clear the cache (`mise cache clear`) to force a clean rebuild
Example fix
// before: another job deletes .env mid-run // after: serialize jobs or watch a stable file mise run dev # retry, cache regenerated
Defensive patterns
Strategy: retry
Validate before calling
// ensure files are stable before loading cache
for (const f of watchFiles) { try { fs.statSync(f); } catch { await waitForFile(f); } } Type guard
const statable = (f) => { try { fs.statSync(f); return true; } catch { return false; } }; Try / catch
try { loadEnvCache() } catch (e) { if (String(e).includes('could not get mtime')) { await sleep(50); loadEnvCache(); } else { throw e; } } Prevention
- Don't delete or swap watched files while mise runs
- Avoid symlink churn on watched config files
- Fix permissions so stat works on watched files
- Retry on transient stat failures
When it happens
Trigger: env_cache::load validation where path.exists() is true but get_file_mtime(path) yields None — typically a race where the file is deleted between the two calls, or filesystem/stat errors (broken symlink target change, permission issues on stat).
Common situations: Concurrent processes deleting/replacing watched files while mise loads the cache; files swapped with symlinks pointing at a missing target; unusual filesystems or restricted permissions on stat.
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
- action prediction payload is too large
- task action manifest has an invalid identity
- task action manifest contains duplicate predictions
- remote action manifest keys must use blake3
- remote action manifest ETag does not match its body
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/2d2c3fe6e627a5e4.
Report an issue: GitHub.