leptos-rs/leptos · error

failed to read hash file

Error message

failed to read hash file

What it means

HashedStylesheet reads an optional hash file that maps asset names to content hashes (e.g. "css:<hash>") to locate the hashed CSS output. If the file exists at the configured path but cannot be read (permissions, race where it disappears, IO error), the expect panics with "failed to read hash file". The library treats an existing-but-unreadable hash file as an unrecoverable configuration error.

Source

Thrown at meta/src/stylesheet.rs:67

    options: LeptosOptions,
    /// An ID for the stylesheet.
    #[prop(optional, into)]
    id: Option<String>,
    /// A base url, not including a trailing slash
    #[prop(optional, into)]
    root: Option<String>,
) -> impl IntoView {
    let mut css_file_name = options.output_name.to_string();
    if options.hash_files {
        let hash_path = std::env::current_exe()
            .map(|path| {
                path.parent().map(|p| p.to_path_buf()).unwrap_or_default()
            })
            .unwrap_or_default()
            .join(options.hash_file.as_ref());
        if hash_path.exists() {
            let hashes = std::fs::read_to_string(&hash_path)
                .expect("failed to read hash file");
            for line in hashes.lines() {
                let line = line.trim();
                if !line.is_empty() {
                    if let Some((file, hash)) = line.split_once(':') {
                        if file == "css" {
                            css_file_name
                                .push_str(&format!(".{}", hash.trim()));
                        }
                    }
                }
            }
        }
    }
    css_file_name.push_str(".css");
    let pkg_path = &options.site_pkg_dir;
    let root = root.unwrap_or_default();

    link()

View on GitHub (pinned to 32d20f6c9d)

Solutions

  1. Verify the hash file path in HashedStylesheet options points at a readable, UTF-8 text file produced by the asset build.
  2. Check file permissions/ownership so the server process can read it (chmod/chown).
  3. Remove the hash_file option or delete the stale file if you don't need hashed CSS lookup — the code skips reading when the file doesn't exist.
  4. Re-run the CSS build pipeline (e.g. cargo-leptos style build) to regenerate the hash file before starting the server.

Example fix

// before: stale path
HashedStylesheet::new(options.hash_file("target/hash-file.txt"), "/pkg")

// after: ensure file is generated and readable, or omit
HashedStylesheet::new(options, "/pkg") // with hash file regenerated by build step
Defensive patterns

Strategy: validation

Validate before calling

let hash_path = compute_hash_path(options);
if hash_path.exists() {
    std::fs::read_to_string(&hash_path)
        .map_err(|e| anyhow!("hash file unreadable: {e}"))?;
}

Type guard

fn hash_file_readable(path: &Path) -> bool {
    path.is_file() && std::fs::read_to_string(path).is_ok()
}

Prevention

When it happens

Trigger: options.hash_file is set, hash_path.exists() returns true, but std::fs::read_to_string fails — permission denied, file deleted between exists() check and read, path is a directory, or invalid UTF-8 content.

Common situations: Docker containers copying build artifacts with wrong ownership, CI caching a hash file that's later pruned, running the server as a non-root user without read access to target/ assets, or a stale hash_file option pointing at a removed intermediate file.

Related errors


AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01). Data as JSON: /api/errors/f0481c962a62a150. Report an issue: GitHub.