wasmerio/wasmer · error

journal restore error: failed to remove directory - {err}

Error message

journal restore error: failed to remove directory - {err}

What it means

apply_path_remove_directory replays a PathRemoveDirectory entry by calling path_remove_directory_internal; any error propagates into this bail. The directory removal recorded in the journal could not be reproduced, so the restored filesystem state would diverge from the snapshot and restore stops.

Source

Thrown at lib/wasix/src/journal/effector/syscalls/path_remove_directory.rs:41

    pub fn apply_path_remove_directory(
        ctx: &mut FunctionEnvMut<'_, WasiEnv>,
        fd: Fd,
        path: &str,
    ) -> anyhow::Result<()> {
        // see `VIRTUAL_ROOT_FD` for details as to why this exists
        if fd == VIRTUAL_ROOT_FD {
            ctx.data().state.fs.root_fs.remove_dir(Path::new(path))?;
        } else {
            let base_dir = ctx.data().state.fs.get_fd(fd).map_err(|err| {
                anyhow::format_err!(
                    "journal restore error: invalid directory descriptor (fd={fd}) - {err}"
                )
            })?;
            if let Err(err) =
                crate::syscalls::path_remove_directory_internal(ctx, fd, base_dir, path)
            {
                bail!("journal restore error: failed to remove directory - {err}");
            }
        }
        Ok(())
    }
}

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Make the restore environment's filesystem state match the snapshot state at capture time (recreate expected contents).
  2. Grant write/remove rights to the relevant preopen directory.
  3. Ensure journals replay in order so prior entries (files created inside the dir) are applied first.
  4. Retake the snapshot from an environment consistent with the restore target.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check that the recorded removals are still reproducible
for op in journal.remove_directory_entries() {
    let p = env.resolve_preopen_path(op.fd, &op.path)
        .ok_or_else(|| anyhow::anyhow!("invalid dir fd {} for restore", op.fd))?;
    // dir must exist and be removable at replay time
    if !std::path::Path::new(&p).is_dir() {
        return Err(anyhow::anyhow!("directory '{}' missing; replay state diverged", p));
    }
}

Type guard

fn is_removable_dir(p: &std::path::Path) -> bool {
    std::fs::read_dir(p).map(|mut d| d.next().is_none()).unwrap_or(false)
}

Try / catch

match restore_from_journal(&env, &journal) {
    Err(e) if e.to_string().contains("failed to remove directory") => {
        eprintln!("dir removal replay failed: {e}; check journal order and fs state");
        resume_with_fresh_snapshot()?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Journal restore replaying PathRemoveDirectory when the target directory doesn't exist (Noent), is not empty (Notempty), the fd is invalid, or the filesystem lacks permission for removal.

Common situations: Restoring into a fresh/already-cleaned filesystem where the directory is already gone; a directory recreated or populated by other restore steps (Notempty); read-only or capability-restricted mounts.

Related errors


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/3f6f17795623a05b. Report an issue: GitHub.