wasmerio/wasmer · error · panic

wasi::path_unlink_file for Buffer

Error message

wasi::path_unlink_file for Buffer

What it means

The wasi path_unlink_file syscall does not handle buffer-backed inodes. In path_unlink_file_internal, the match arms handle symlink/file removal via the FS layer, but the catch-all _ arm hits unimplemented! when the target inode (or matched kind) is a Buffer. Unlinking buffer nodes was simply never implemented.

Source

Thrown at lib/wasix/src/syscalls/wasi/path_unlink_file.rs:135

                        wasi_try_ok!(h.unlink().map_err(fs_error_into_wasi_err));
                    } else {
                        // File is closed
                        // problem with the abstraction, we can't call unlink because there's no handle
                        // drop mutable borrow on `path`
                        let path = path.clone();
                        drop(guard);
                        wasi_try_ok!(state.fs_remove_file(path));
                    }
                }
                Kind::Dir { .. } | Kind::Root { .. } => return Ok(Errno::Isdir),
                Kind::Symlink { .. } => {
                    drop(guard);
                    let errno = state.fs.remove_symlink_file(host_adjusted_path.as_path());
                    if errno != Errno::Success {
                        return Ok(errno);
                    }
                }
                _ => unimplemented!("wasi::path_unlink_file for Buffer"),
            }
        }
    }

    Ok(Errno::Success)
}

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Remove the buffer node through the buffer-management API (drop/replace it in the FS tree) instead of path_unlink_file.
  2. Pre-check the resolved inode Kind and return Errno::Notsup for buffers instead of calling through.
  3. Register such blobs as Kind::File if unlink semantics are required.
  4. Implement the Buffer arm by detaching the buffer from its parent directory.

Example fix

// before
path_unlink_file("/memfs/tmp.bin") // tmp.bin is a Buffer -> panic

// after (guard)
if matches!(&*inode.read(), Kind::Buffer { .. }) {
    return Ok(Errno::Notsup);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// resolve and check the kind before unlinking
fn unlinkable(state: &FsState, path: &Path) -> bool {
    match state.fs.get_inode_at_path(path) {
        Ok(inode) => !matches!(&*inode.read(), Kind::Buffer { .. }),
        Err(_) => false,
    }
}

Type guard

fn is_buffer_inode(inode: &Inode) -> bool {
    matches!(&*inode.read(), Kind::Buffer { .. })
}

Try / catch

let r = std::panic::catch_unwind(AssertUnwindSafe(|| path_unlink_file_internal(state, path, follow))); 
if r.is_err() { return Ok(Errno::Notsup); }

Prevention

When it happens

Trigger: Guest calls wasi.path_unlink_file on a path that resolves to a Kind::Buffer node in the synthetic FS tree (e.g. an in-memory blob registered as a Buffer), instead of a regular file or symlink.

Common situations: Guests that 'clean up' temp files inside preopened in-memory filesystems where drivers create Buffer nodes; apps ported from other wasi runtimes where buffers are deletable.

Related errors


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