{"record":{"id":"6094a8b37ba917b1","repo":"wasmerio/wasmer","slug":"journal-restore-error-failed-to-close-descriptor","errorCode":null,"errorMessage":"journal restore error: failed to close descriptor (fd={fd}) - {}","messagePattern":"journal restore error: failed to close descriptor \\(fd=(.+?)\\) - (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/wasix/src/journal/effector/syscalls/fd_close.rs","lineNumber":19,"sourceCode":"use super::*;\nuse crate::syscalls::flush_captured_handle;\n\nimpl JournalEffector {\n    pub fn save_fd_close(ctx: &mut FunctionEnvMut<'_, WasiEnv>, fd: Fd) -> anyhow::Result<()> {\n        Self::save_event(ctx, JournalEntry::CloseFileDescriptorV1 { fd })\n    }\n\n    pub fn apply_fd_close(ctx: &mut FunctionEnvMut<'_, WasiEnv>, fd: Fd) -> anyhow::Result<()> {\n        let env = ctx.data();\n        let (_, state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };\n        let outcome = state.fs.close_fd_and_capture_flush(fd);\n\n        if outcome.skipped_preopen {\n            return Ok(());\n        }\n\n        if !outcome.removed {\n            bail!(\n                \"journal restore error: failed to close descriptor (fd={fd}) - {}\",\n                Errno::Badf\n            );\n        }\n\n        flush_captured_handle(env, outcome.flush_target).map_err(|err| {\n            anyhow::anyhow!(\n                \"journal restore error: failed to flush before closing descriptor (fd={fd}) - {err:?}\"\n            )\n        })?;\n\n        Ok(())\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/journal/effector/syscalls/fd_close.rs#L1-L34","documentation":"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.","triggerScenarios":"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.","commonSituations":"Restoring journals against an environment whose preopened fds differ from the snapshot; duplicate close entries; runtime drift between snapshot and restore versions.","solutions":["Regenerate the snapshot/journal and restore from the new one.","Check that preopen configuration (stdin/stdout/stderr/mounted dirs) matches the environment used when the journal was captured.","Confirm the same wasix version is used for capture and restore.","Verify the journal isn't being replayed twice or out of order."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify preopen layout matches before restore\nif env.preopen_fds() != journal.initial_preopen_fds() {\n    return Err(anyhow::anyhow!(\"preopen fd layout differs from snapshot; align --mapdir/stdio flags\"));\n}","typeGuard":null,"tryCatchPattern":"match restore_from_journal(&env, &journal) {\n    Err(e) if e.to_string().contains(\"failed to close descriptor\") => {\n        eprintln!(\"fd already closed/absent during restore: {e}; continuing with fresh snapshot\");\n        resume_with_fresh_snapshot()?;\n    }\n    other => other?,\n}","preventionTips":["Match preopen configuration (mapdirs, stdio) between capture and restore.","Never replay a journal twice over the same environment.","Retake snapshots when switching runtime versions."],"tags":["wasix","journal","fd-close","snapshot-restore"],"backgroundTag":"journal-restore-failed","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}