sinelaw/fresh · error

Could not determine cache directory

Error message

Could not determine cache directory

What it means

extract_plugins needs a base cache directory to atomically stage extracted embedded plugins (via rename). If get_cache_dir() returns None (no XDG_CACHE_HOME, no HOME, and no fallback the helper recognizes), it returns io::ErrorKind::NotFound 'Could not determine cache directory'.

Solutions

  1. Set XDG_CACHE_HOME (or HOME) to a writable directory before launching
  2. Launch the editor with a proper user environment (avoid env -i / sanitized service units without Environment=HOME=...)
  3. Make the caller handle the None case with an explicit fallback (e.g. std::env::temp_dir())
  4. Pre-extract plugins so the runtime extraction path is not needed

Example fix

// before
std::process::Command::new("fresh-editor").env_clear().spawn()?;
// after
std::process::Command::new("fresh-editor")
    .env("XDG_CACHE_HOME", "/home/dev/.cache")
    .spawn()?;
Defensive patterns

Strategy: fallback

Validate before calling

fn cache_dir_resolvable() -> bool {
    std::env::var_os("XDG_CACHE_HOME").filter(|v| !v.is_empty()).is_some()
        || std::env::var_os("HOME").filter(|v| !v.is_empty()).is_some()
}

Try / catch

match get_embedded_plugins_dir() {
    Ok(dir) => dir,
    Err(e) if e.kind() == io::ErrorKind::NotFound => {
        std::env::set_var("XDG_CACHE_HOME", "/tmp/fresh-cache");
        get_embedded_plugins_dir()?
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling get_embedded_plugins_dir()/extract_plugins() in an environment where the cache directory cannot be resolved: service accounts without HOME, sanitized environment (systemd, cron, containers), or XDG_CACHE_HOME set to an empty/invalid value.

Common situations: Running the editor under systemd or a container runtime that strips HOME/XDG vars; CI jobs with minimal env; launching via a wrapper script that clears the environment.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/3ee0891ac4ec6b42. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/services/plugins/embedded.rs:68

/// Get the cache directory for extracted plugins
fn get_cache_dir() -> Option<PathBuf> {
    dirs::cache_dir().map(|p| p.join("fresh").join("embedded-plugins"))
}

/// Extract embedded plugins to the cache directory.
///
/// Concurrency contract: this function is called via a process-local
/// `OnceLock`, but multiple test processes (e.g. cargo-nextest) may
/// each call it concurrently against the same on-disk directory. We
/// publish atomically: extract into a sibling `.pending.<pid>.<nanos>`
/// directory, write a `.extracted` marker, then `rename` into place.
/// `rename` over an existing non-empty directory fails on POSIX, so
/// only one publisher wins; losers fall back to the winner's
/// directory. Readers gate on the marker file so they never observe a
/// half-extracted tree.
fn extract_plugins() -> Result<PathBuf, std::io::Error> {
    let cache_base = get_cache_dir().ok_or_else(|| {
        std::io::Error::new(
            std::io::ErrorKind::NotFound,
            "Could not determine cache directory",
        )
    })?;

    let content_hash = PLUGINS_CONTENT_HASH.trim();
    let cache_dir = cache_base.join(content_hash);
    let marker = cache_dir.join(".extracted");

    if marker.exists() {
        tracing::info!("Using cached embedded plugins from: {:?}", cache_dir);
        return Ok(cache_dir);
    }

    tracing::info!("Extracting embedded plugins to: {:?}", cache_dir);
    std::fs::create_dir_all(&cache_base)?;

    let pid = std::process::id();

View on GitHub (pinned to 67894ca546)