GitoxideLabs/gitoxide · error

non zero

Error message

non zero

What it means

`gix_pack::cache::object::MemoryCappedHashmap::new` requires a non-zero memory cap because the underlying clru cache is built from a `NonZeroUsize`. A cap of 0 bytes would create a cache that can never hold an item, so the constructor panics with 'non zero'.

Solutions

  1. Provide a non-zero byte value for the memory cap
  2. Clamp the value before construction: `cap.max(1)` or substitute a default when 0
  3. Skip cache construction entirely if a 0 cap means 'disabled' in your app

Example fix

// before
let cache = object::MemoryCappedHashmap::new(bytes);
// after
let cache = if bytes == 0 { None } else { Some(object::MemoryCappedHashmap::new(bytes)) };
Defensive patterns

Strategy: validation

Validate before calling

let cap = if bytes == 0 { DEFAULT_OBJECT_CACHE_BYTES } else { bytes };

Prevention

When it happens

Trigger: Calling `gix_pack::cache::object::MemoryCappedHashmap::new(0)` — typically when a configured object-cache size in bytes is 0.

Common situations: Users setting `object-cache-memory-bytes = 0` in config expecting to disable caching; config defaults resolved to 0.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/95b00d16d73233ac. Report an issue: GitHub.

Appendix: source

Thrown at gix-pack/src/cache/object.rs:45

    /// An LRU cache with hash map backing and an eviction rule based on the memory usage for object data in bytes.
    pub struct MemoryCappedHashmap {
        inner: clru::CLruCache<Key, Entry, gix_hashtable::hash::Builder, CustomScale>,
        free_list: Vec<Vec<u8>>,
        debug: gix_features::cache::Debug,
    }

    impl MemoryCappedHashmap {
        /// The amount of bytes we can hold in total, or the value we saw in `new(…)`.
        pub fn capacity(&self) -> usize {
            self.inner.capacity()
        }
        /// Return a new instance which evicts least recently used items if it uses more than `memory_cap_in_bytes`
        /// object data.
        pub fn new(memory_cap_in_bytes: usize) -> MemoryCappedHashmap {
            MemoryCappedHashmap {
                inner: clru::CLruCache::with_config(
                    clru::CLruCacheConfig::new(NonZeroUsize::new(memory_cap_in_bytes).expect("non zero"))
                        .with_hasher(gix_hashtable::hash::Builder)
                        .with_scale(CustomScale),
                ),
                free_list: Vec::new(),
                debug: gix_features::cache::Debug::new(format!("MemoryCappedObjectHashmap({memory_cap_in_bytes}B)")),
            }
        }
    }

    impl cache::Object for MemoryCappedHashmap {
        /// Put the object going by `id` of `kind` with `data` into the cache.
        fn put(&mut self, id: gix_hash::ObjectId, kind: gix_object::Kind, data: &[u8]) {
            self.debug.put();
            let Some(data) = set_vec_to_slice(self.free_list.pop().unwrap_or_default(), data) else {
                return;
            };
            let res = self.inner.put_with_weight(id, Entry { data, kind });
            match res {

View on GitHub (pinned to e73179060b)