leptos-rs/leptos · critical
failed to read hash file
Error message
failed to read hash file
What it means
In HydrationScripts, when a hash_file is configured, leptos reads the file (site-root dir joined with options.hash_file) via std::fs::read_to_string and unwraps with expect("failed to read hash file"). The panic means the configured hash file is missing or unreadable at the joined path. It only runs when hash_file is set in env options.
Source
Thrown at leptos/src/hydration/mod.rs:73
/// A base url, not including a trailing slash
#[prop(optional, into)]
root: Option<String>,
) -> impl IntoView {
static SPLIT_MANIFEST: OnceLock<Option<WasmSplitManifest>> =
OnceLock::new();
if let Some(splits) = SPLIT_MANIFEST.get_or_init(|| {
let root = root.clone().unwrap_or_default();
let (wasm_split_js, wasm_split_manifest) = 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());
let hashes = std::fs::read_to_string(&hash_path)
.expect("failed to read hash file");
let mut split =
"__wasm_split.______________________.js".to_string();
let mut manifest = "__wasm_split_manifest.json".to_string();
for line in hashes.lines() {
let line = line.trim();
if !line.is_empty() {
if let Some((file, hash)) = line.split_once(':') {
if file == "manifest" {
manifest.clear();
manifest.push_str("__wasm_split_manifest.");
manifest.push_str(hash.trim());
manifest.push_str(".json");
}
if file == "split" {
split.clear();
split.push_str("__wasm_split.");
split.push_str(hash.trim());View on GitHub (pinned to 32d20f6c9d)
Solutions
- Ensure the hash file named by hash_file exists under the configured site root directory before starting the server.
- Run the binary from the directory containing the hash file, or set the site-root env option to the correct absolute path.
- Copy the hash file in your deploy artifact/build script (it is emitted alongside the wasm-split output).
- If you do not use wasm splitting, remove the hash_file option so this code path is skipped.
Example fix
// before
options.hash_file = Some("dist/hash.txt".into()); // file never generated
// after
cargo leptos build # generates dist/hash.txt, or unset hash_file when unused
Defensive patterns
Strategy: validation
Validate before calling
let p = std::path::Path::new(&site_root).join(hash_file);
assert!(p.is_file(), "hash file missing at {}", p.display());
std::fs::read_to_string(&p).expect("hash file unreadable");
Prevention
- Bundle the hash file with the server deploy artifact
- Point LEPTOS_SITE_ROOT at the directory that actually contains build outputs
- Start the binary from a known cwd or use absolute site-root paths
- Add a startup health check that reads the hash file before serving
When it happens
Trigger: Using HydrationScripts with the hash_file option set while the file at {site_dir}/{hash_file} does not exist, or the binary's cwd differs from the site root so the relative join resolves elsewhere.
Common situations: Deploying the server binary without bundling the .hash / wasm-split hash file; running the server from a different working directory than in dev; hash_file path configured as absolute but joined onto site_dir incorrectly; a build that never generated hashes because wasm-split was disabled.
Related errors
- lazy routes should not be used with hydrate_body(); use hydr
- could not read manifest file
- no current reactive Owner found
- there to be a <html> element
- missing <head> element
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/35d5d1b7c72a6ef3.
Report an issue: GitHub.