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
- Verify the hash file path in HashedStylesheet options points at a readable, UTF-8 text file produced by the asset build.
- Check file permissions/ownership so the server process can read it (chmod/chown).
- 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.
- 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
- Generate the hash file in the build pipeline before the server starts.
- Ensure container/CI file ownership allows the server user to read build assets.
- Remove or clear the hash_file option if you don't need hashed stylesheet lookup.
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
- Reading from a LocalResource outside Suspense in `ssr` mode
- Expected a [number, string] tuple
- failed to read hash file
- body to exist
- no shared context
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/f0481c962a62a150.
Report an issue: GitHub.