gitbutlerapp/gitbutler · error
Could not get app cache dir
Error message
Could not get app cache dir
What it means
`app_cache_dir_for_channel` returns this when `dirs::cache_dir()` is None — no platform cache directory could be determined. On Linux this requires `XDG_CACHE_HOME` or a resolvable home dir (`$HOME/.cache` fallback); on macOS it needs a home dir. Setting `E2E_TEST_APP_DATA_DIR` returns `<test_dir>/cache` before this check runs.
Source
Thrown at crates/but-path/src/lib.rs:142
/// the compile-time or explicit channel.
///
/// # Errors
///
/// Returns an error if the platform's cache directory cannot be determined.
pub fn app_cache_dir() -> anyhow::Result<PathBuf> {
app_cache_dir_for_channel(AppChannel::new())
}
/// Like [`app_cache_dir()`], but explicitly for `channel`.
///
/// When `E2E_TEST_APP_DATA_DIR` is set, `channel` is ignored and the result is always
/// `<E2E_TEST_APP_DATA_DIR>/cache`.
pub fn app_cache_dir_for_channel(channel: AppChannel) -> anyhow::Result<PathBuf> {
if let Some(test_dir) = std::env::var_os("E2E_TEST_APP_DATA_DIR") {
return Ok(PathBuf::from(test_dir).join("cache"));
}
dirs::cache_dir()
.ok_or(anyhow::anyhow!("Could not get app cache dir"))
.map(|dir| dir.join(identifier_for_channel(channel)))
}
/// Returns the bundle identifier for the compile-time [`AppChannel`].
pub fn identifier() -> &'static str {
identifier_for_channel(AppChannel::new())
}
/// Returns the bundle identifier used for `channel`.
pub const fn identifier_for_channel(channel: AppChannel) -> &'static str {
match channel {
AppChannel::Nightly => "com.gitbutler.app.nightly",
AppChannel::Release => "com.gitbutler.app",
AppChannel::Dev => "com.gitbutler.app.dev",
}
}
/// A way to learn about the currently configured compile-time app-channel.View on GitHub (pinned to caf1f223d3)
Solutions
- Set `HOME` or `XDG_CACHE_HOME` to a writable location in that environment
- Set `E2E_TEST_APP_DATA_DIR` in test/CI contexts to get a deterministic cache path
- Configure the service unit with an explicit HOME (e.g. `Environment="HOME=/var/cache/gitbutler"`)
- Treat cache-dir failure as non-fatal where possible: log and continue without cacheable features (update checks) instead of aborting startup
Example fix
// before
let dir = but_path::app_cache_dir()?; // Could not get app cache dir
// after (degrade gracefully — cache is non-essential)
let cache = match but_path::app_cache_dir() {
Ok(dir) => Some(dir),
Err(e) => {
log::warn!("no cache dir ({e:#}); skipping cached features");
None
}
}; Defensive patterns
Strategy: fallback
Validate before calling
fn cache_dir_available() -> bool {
std::env::var_os("XDG_CACHE_HOME").is_some() || dirs::home_dir().is_some()
} Try / catch
let cache = match but_path::app_cache_dir() {
Ok(dir) => Some(dir),
Err(e) => {
log::warn!("no cache dir; cached features disabled ({e:#})");
None // cache is non-essential by design
}
}; Prevention
- Treat cache-dir failure as degradation, not fatal — the docs mark cache data as regenerable
- Set HOME/XDG_CACHE_HOME in service units
- Use E2E_TEST_APP_DATA_DIR to make cache paths deterministic under test
When it happens
Trigger: App or `but` binary running where HOME is unset and passwd lookup fails: minimal containers, systemd services without HOME, scrubbed cron environments. Also tooling that clears env vars for sandboxing.
Common situations: Headless CI, dockerized usage of the GitButler crates, launchd/systemd units missing environment configuration, portable/readonly-root environments.
Related errors
- Could not get app data dir
- Failed to determine home directory
- When using OpenAI in a bring your own key configuration, you
- FATAL: Couldn't open in-memory URL: {path_err}
- just set the value
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/4c5fe70dd5932c41.
Report an issue: GitHub.