wasmerio/wasmer · error

journal restore error: failed to close descriptor (fd={fd})

Error message

journal restore error: failed to close descriptor (fd={fd}) - {}

What it means

apply_fd_close replays an FdClose journal entry; the close outcome reports that the descriptor was not actually removed from the fd table (outcome.removed == false), so restore cannot reproduce the snapshotted state. The error is raised with Errno::Badf to indicate a bad/unknown descriptor.

Source

Thrown at lib/wasix/src/journal/effector/syscalls/fd_close.rs:19

use super::*;
use crate::syscalls::flush_captured_handle;

impl JournalEffector {
    pub fn save_fd_close(ctx: &mut FunctionEnvMut<'_, WasiEnv>, fd: Fd) -> anyhow::Result<()> {
        Self::save_event(ctx, JournalEntry::CloseFileDescriptorV1 { fd })
    }

    pub fn apply_fd_close(ctx: &mut FunctionEnvMut<'_, WasiEnv>, fd: Fd) -> anyhow::Result<()> {
        let env = ctx.data();
        let (_, state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
        let outcome = state.fs.close_fd_and_capture_flush(fd);

        if outcome.skipped_preopen {
            return Ok(());
        }

        if !outcome.removed {
            bail!(
                "journal restore error: failed to close descriptor (fd={fd}) - {}",
                Errno::Badf
            );
        }

        flush_captured_handle(env, outcome.flush_target).map_err(|err| {
            anyhow::anyhow!(
                "journal restore error: failed to flush before closing descriptor (fd={fd}) - {err:?}"
            )
        })?;

        Ok(())
    }
}

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Regenerate the snapshot/journal and restore from the new one.
  2. Check that preopen configuration (stdin/stdout/stderr/mounted dirs) matches the environment used when the journal was captured.
  3. Confirm the same wasix version is used for capture and restore.
  4. Verify the journal isn't being replayed twice or out of order.
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify preopen layout matches before restore
if env.preopen_fds() != journal.initial_preopen_fds() {
    return Err(anyhow::anyhow!("preopen fd layout differs from snapshot; align --mapdir/stdio flags"));
}

Try / catch

match restore_from_journal(&env, &journal) {
    Err(e) if e.to_string().contains("failed to close descriptor") => {
        eprintln!("fd already closed/absent during restore: {e}; continuing with fresh snapshot");
        resume_with_fresh_snapshot()?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: Journal restore attempting to close an fd that no longer exists or is a preopen that cannot be removed (skipped_preopen path excluded), i.e. fd_close_internal did not remove the descriptor.

Common situations: Restoring journals against an environment whose preopened fds differ from the snapshot; duplicate close entries; runtime drift between snapshot and restore versions.

Related errors


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