sxyazi/yazi · error · io::Error
{e}
Error message
{e} What it means
On Windows, `Trash::new()` initializes the COM library via a thread-local `COM` holder; if COM initialization failed, the stored error's kind and message are rethrown as an io::Error. This means the process could not use COM (required for the Windows shell trash APIs), so no trash operations can proceed. The message is the underlying COM initialization error string.
Source
Thrown at yazi-fs/src/trash/windows/trash.rs:18
use std::{fs, io, os::windows::ffi::OsStrExt, path::{Path, PathBuf}, time::{Duration, SystemTime, UNIX_EPOCH}};
use windows::{Win32::{Foundation::*, System::Com::*, UI::Shell::*}, core::PCWSTR};
use yazi_ffi::Com;
use super::{super::{TrashEntries, TrashEntry, TrashId}, shell_item::ShellItem, trash_sig::TrashSig};
use crate::{cha::Cha, file::File};
thread_local! {
static COM: io::Result<Com> = Com::new();
}
pub struct Trash;
impl Trash {
pub(crate) fn new() -> io::Result<Self> {
COM.with(|result| {
result.as_ref().map(|_| Self).map_err(|e| io::Error::new(e.kind(), e.to_string()))
})
}
pub(crate) fn list(&self, entry: Option<&TrashEntry>) -> io::Result<Vec<TrashEntry>> {
let Some(entry) = entry else {
return self.tops();
};
if !entry.lcha.is_dir() || entry.lcha.is_indirect() {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "trash item is not a directory"));
}
let original = entry.original.as_deref().ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "trash item has no put-back location")
})?;
self
.resolve(entry)?View on GitHub (pinned to 5f901b886b)
Solutions
- Inspect the underlying error kind: RPC_E_CHANGED_MODE means call Trash APIs on a thread that initializes COM with the matching apartment model (or run on a dedicated thread).
- Avoid initializing COM as STA on threads that will use the trash; let yazi's COM wrapper initialize it first.
- Retry construction on a fresh thread where COM can be initialized in the required mode.
- Check for memory pressure if the error is E_OUTOFMEMORY.
Example fix
// before
let trash = Trash::new()?;
// after
let trash = Trash::new().map_err(|e| {
eprintln!("COM init failed ({e}); running trash ops on a dedicated thread");
e
})?; Defensive patterns
Strategy: try-catch
Validate before calling
// ensure COM init succeeded before use
let trash = Trash::new().map_err(|e| anyhow!("COM init failed: {e}"))?; Type guard
fn com_ready(r: &Result<Trash, std::io::Error>) -> bool { r.is_ok() } Try / catch
match Trash::new() {
Ok(t) => t,
Err(e) => {
// RPC_E_CHANGED_MODE -> retry on a thread with correct apartment model
log::error!("COM init failed: {e}");
return;
}
} Prevention
- Don't initialize COM as STA on threads that will use trash APIs.
- Let yazi's COM wrapper perform first initialization per thread.
- Run trash operations on a dedicated worker thread if embedding.
When it happens
Trigger: Constructing `Trash::new()` on Windows when the thread-local COM init previously failed — e.g. CoInitializeEx returning RPC_E_CHANGED_MODE (COM already initialized with a different threading model, commonly STA) or E_OUTOFMEMORY.
Common situations: Embedding yazi code in a process that already initialized COM as single-threaded apartment; calling Trash APIs from a thread with conflicting COM apartment requirements; rare resource exhaustion.
Related errors
AI-assisted analysis of sxyazi/yazi@5f901b886b (2026-09-02).
Data as JSON: /api/errors/d2059d11ac3c2ade.
Report an issue: GitHub.