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

  1. Point git_pack_cache_path at a writable, real (non-symlink) directory owned by the relay user
  2. Set git_pack_cache_max_concurrent_populations to at least 1
  3. Check disk space and filesystem health (df, mount flags) on the cache volume
  4. 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

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


AI-assisted analysis of block/buzz@dad5a33865 (2026-08-20). Data as JSON: /api/errors/c40ddfd00a585abd. Report an issue: GitHub.