block/buzz · critical
git pack cache path must be available
Error message
git pack cache path must be available
What it means
AppState::new constructs a GitPackCache under config.git_pack_cache_path. GitPackCache::new (crates/buzz-relay/src/api/git/pack_cache.rs:107) fails when git_pack_cache_max_concurrent_populations is 0, the cache directory cannot be created (permission, missing parent, ENOSPC), stat fails, or the path is a symlink (explicitly rejected for safety). The expect turns any of those into a startup panic of the whole relay.
Source
Thrown at crates/buzz-relay/src/state.rs:859
}
tracing::warn!("audit log worker exited (expected on shutdown)");
});
let git_max_concurrent_ops = config.git_max_concurrent_ops;
let media_max_concurrent_uploads = config.media_max_concurrent_uploads;
let git_store = crate::api::git::store::GitStore::new(
&config.media.s3_endpoint,
&config.media.s3_access_key,
&config.media.s3_secret_key,
&config.media.s3_bucket,
&config.media.s3_region,
config.media.s3_addressing_style,
)
.expect("media storage was already constructed with this S3 config");
let git_pack_cache = Arc::new(
crate::api::git::pack_cache::GitPackCache::new(
&config.git_pack_cache_path,
config.git_pack_cache_max_bytes,
config.git_pack_cache_max_concurrent_populations,
)
.expect("git pack cache path must be available"),
);
let nip98_replay: Arc<dyn Nip98ReplayGuard> =
Arc::new(RedisNip98ReplayGuard::new(redis_pool.clone()));
let gif_http_client = crate::api::gifs::build_gif_http_client();
let admission_rate_limiter = Arc::new(RedisRateLimiter::new(redis_pool.clone()));
let audit_enabled = audit_arc.is_some();
let state = Self {
config: Arc::new(config),
db,
redis_pool,
audit: audit_arc,
pubsub,
auth: Arc::new(auth),
search: search_arc,
sub_registry: Arc::new(SubscriptionRegistry::new()),View on GitHub (pinned to dad5a33865)
Solutions
- Point git_pack_cache_path at a writable, real (non-symlink) directory owned by the relay user
- Set git_pack_cache_max_concurrent_populations to at least 1
- Check disk space and filesystem health (df, mount flags) on the cache volume
- Propagate the String error out of AppState construction so misconfiguration produces a clean startup error instead of a panic
Example fix
// before
let git_pack_cache = Arc::new(
GitPackCache::new(
&config.git_pack_cache_path,
config.git_pack_cache_max_bytes,
config.git_pack_cache_max_concurrent_populations,
)
.expect("git pack cache path must be available"),
);
// after
let git_pack_cache = Arc::new(
GitPackCache::new(
&config.git_pack_cache_path,
config.git_pack_cache_max_bytes,
config.git_pack_cache_max_concurrent_populations,
)
.map_err(|e| anyhow::anyhow!("git pack cache init: {e}"))?,
); Defensive patterns
Strategy: validation
Validate before calling
// before constructing AppState
let p = std::path::Path::new(&config.git_pack_cache_path);
std::fs::create_dir_all(p).map_err(|e| format!("create git pack cache dir: {e}"))?;
if std::fs::symlink_metadata(p).map_err(|e| e.to_string())?.file_type().is_symlink() {
return Err("git pack cache path must not be a symlink".into());
}
if config.git_pack_cache_max_concurrent_populations == 0 {
return Err("git_pack_cache_max_concurrent_populations must be >= 1".into());
} Prevention
- Provision the cache directory in deployment manifests (emptyDir/hostPath with correct fsGroup) rather than relying on runtime creation
- Never symlink the cache path — mount the real volume directly
- Add a startup readiness check that validates writable cache, DB, and Redis together so config failures surface before traffic
When it happens
Trigger: git_pack_cache_path on a read-only volume or a directory the relay user cannot write; the path being a symlink (e.g. /var/cache/buzz -> /mnt/data); git_pack_cache_max_concurrent_populations set to 0; disk full when creating the session tempdir.
Common situations: Kubernetes deployments mounting a read-only or wrongly-owned cache volume; operators symlinking the cache to a larger disk; container runs where the configured path exists but belongs to root; env-var typos falling back to a default path that is unwritable in the image.
Related errors
- oauth cache is not a regular file
- oauth cache path has no parent directory
- BUZZ_UDS_PATH {uds_path} exists but is not a socket
- Failed to bind UDS {uds_path}: {e}
- failed to install rustls crypto provider
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-20).
Data as JSON: /api/errors/c40ddfd00a585abd.
Report an issue: GitHub.