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

  1. Ensure the hash file named by hash_file exists under the configured site root directory before starting the server.
  2. Run the binary from the directory containing the hash file, or set the site-root env option to the correct absolute path.
  3. Copy the hash file in your deploy artifact/build script (it is emitted alongside the wasm-split output).
  4. 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

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


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