sinelaw/fresh · error · io::Error (NotFound)

Could not determine data directory

Error message

Could not determine data directory

What it means

get_data_dir() fails when the OS data directory cannot be determined via dirs::data_dir(). Unless a test override (DATA_DIR_OVERRIDE) is installed, the function must resolve the platform data dir to build `$XDG_DATA_HOME/fresh`. This is the standalone data-dir resolver used throughout the editor.

Solutions

  1. Set XDG_DATA_HOME or HOME in the environment.
  2. In tests, install DATA_DIR_OVERRIDE (thread-local override) to a tempdir before calling get_data_dir().
  3. Fix the service/container definition to provide a writable home.

Example fix

// before
let dir = get_data_dir()?;
// after
DATA_DIR_OVERRIDE.with(|s| *s.borrow_mut() = Some(tempdir.path().to_path_buf()));
let dir = get_data_dir()?;
Defensive patterns

Strategy: try-catch

Validate before calling

if dirs::data_dir().is_none() {
    eprintln!("no data dir resolvable; set XDG_DATA_HOME or override in test");
}

Try / catch

match get_data_dir() {
    Ok(dir) => dir,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        let tmp = std::env::temp_dir().join("fresh-fallback");
        std::fs::create_dir_all(&tmp)?;
        tmp
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling get_data_dir() with DATA_DIR_OVERRIDE unset and dirs::data_dir() returning None (no XDG_DATA_HOME, no HOME, or non-standard platform).

Common situations: CI runners or containers with HOME unset; integration tests that forgot to set the override and run in a bare 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/e592cff9ceb44545. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor-core/src/data_dir.rs:55

/// the override has to move with it.
///
/// Test-only hook: production never calls this, and with no override installed
/// this costs one thread-local read per lookup. It is `#[doc(hidden)] pub`
/// rather than `#[cfg(test)]` because `#[cfg(test)]` in `fresh-editor-core` is
/// invisible to the integration tests in `fresh-editor` (see CONTRIBUTING,
/// "The data layer is its own crate").
#[doc(hidden)]
pub fn set_data_dir_override(dir: Option<PathBuf>) -> Option<PathBuf> {
    DATA_DIR_OVERRIDE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), dir))
}

/// The `fresh` data directory (`$XDG_DATA_HOME/fresh`, or the platform equivalent).
pub fn get_data_dir() -> std::io::Result<PathBuf> {
    if let Some(dir) = DATA_DIR_OVERRIDE.with(|slot| slot.borrow().clone()) {
        return Ok(dir);
    }
    let data_dir = dirs::data_dir().ok_or_else(|| {
        std::io::Error::new(
            std::io::ErrorKind::NotFound,
            "Could not determine data directory",
        )
    })?;
    Ok(data_dir.join("fresh"))
}

View on GitHub (pinned to 67894ca546)