getzola/zola · error

result cache lock

Error message

result cache lock

What it means

The get_image_metadata template function uses the same shared result_cache Mutex to memoize image metadata lookups. It panics with 'result cache lock' when the mutex is poisoned by a panic on another thread while the lock was held.

Source

Thrown at components/templates/src/functions/images.rs:130

        let allow_missing: bool = kwargs.get("allow_missing")?.unwrap_or(false);

        let (src_path, unified_path) =
            match search_for_file(&self.base_path, &path, &self.theme, &self.output_path)
                .map_err(|e| Error::message(format!("`get_image_metadata`: {}", e)))?
            {
                Some((f, p)) => (f, p),
                None => {
                    if allow_missing {
                        return Ok(Value::none());
                    }
                    return Err(Error::message(format!(
                        "`get_image_metadata`: Cannot find path: {}",
                        path
                    )));
                }
            };

        let mut cache = self.result_cache.lock().expect("result cache lock");
        if let Some(cached_result) = cache.get(&unified_path) {
            return Ok(cached_result.clone());
        }

        let response = imageproc::read_image_metadata(src_path)
            .map_err(|e| Error::message(format!("`get_image_metadata`: {}", e)))?;
        let out = Value::from_serializable(&response);
        cache.insert(unified_path, out.clone());

        Ok(out)
    }
}

#[cfg(test)]
mod tests {
    use super::{GetImageMetadata, ResizeImage};

    use std::path::{Path, PathBuf};

View on GitHub (pinned to 61d3082821)

Solutions

  1. Locate and fix the earlier panic that poisoned the cache (original backtrace precedes this one).
  2. Use unwrap_or_else(|p| p.into_inner()) on the lock to tolerate poisoning.
  3. Restart the build after any image-metadata panic.
  4. Make read_image_metadata paths return errors instead of panicking under the lock.

Example fix

// before
let mut cache = self.result_cache.lock().expect("result cache lock");
// after
let mut cache = self.result_cache.lock().unwrap_or_else(|p| p.into_inner());
Defensive patterns

Strategy: try-catch

Try / catch

let mut cache = match self.result_cache.lock() {
    Ok(g) => g,
    Err(poisoned) => poisoned.into_inner(),
};

Prevention

When it happens

Trigger: A template calls get_image_metadata after result_cache was poisoned — e.g. by a panic in a concurrent get_url/get_image_metadata call in another render thread.

Common situations: Parallel page rendering in zola build/server where one image lookup panicked and subsequent renders hit the poisoned mutex.

Related errors


AI-assisted analysis of getzola/zola@61d3082821 (2026-09-03). Data as JSON: /api/errors/4ce02454e3a2bb24. Report an issue: GitHub.