{"record":{"id":"d2059d11ac3c2ade","repo":"sxyazi/yazi","slug":"e","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/trash/windows/trash.rs","lineNumber":18,"sourceCode":"use std::{fs, io, os::windows::ffi::OsStrExt, path::{Path, PathBuf}, time::{Duration, SystemTime, UNIX_EPOCH}};\n\nuse windows::{Win32::{Foundation::*, System::Com::*, UI::Shell::*}, core::PCWSTR};\nuse yazi_ffi::Com;\n\nuse super::{super::{TrashEntries, TrashEntry, TrashId}, shell_item::ShellItem, trash_sig::TrashSig};\nuse crate::{cha::Cha, file::File};\n\nthread_local! {\n\tstatic COM: io::Result<Com> = Com::new();\n}\n\npub struct Trash;\n\nimpl Trash {\n\tpub(crate) fn new() -> io::Result<Self> {\n\t\tCOM.with(|result| {\n\t\t\tresult.as_ref().map(|_| Self).map_err(|e| io::Error::new(e.kind(), e.to_string()))\n\t\t})\n\t}\n\n\tpub(crate) fn list(&self, entry: Option<&TrashEntry>) -> io::Result<Vec<TrashEntry>> {\n\t\tlet Some(entry) = entry else {\n\t\t\treturn self.tops();\n\t\t};\n\n\t\tif !entry.lcha.is_dir() || entry.lcha.is_indirect() {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidInput, \"trash item is not a directory\"));\n\t\t}\n\n\t\tlet original = entry.original.as_deref().ok_or_else(|| {\n\t\t\tio::Error::new(io::ErrorKind::NotFound, \"trash item has no put-back location\")\n\t\t})?;\n\n\t\tself\n\t\t\t.resolve(entry)?","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/sxyazi/yazi/blob/5f901b886b14de1f17460b6e52e9de5d67f8aba9/yazi-fs/src/trash/windows/trash.rs#L1-L36","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet trash = Trash::new()?;\n// after\nlet trash = Trash::new().map_err(|e| {\n    eprintln!(\"COM init failed ({e}); running trash ops on a dedicated thread\");\n    e\n})?;","handlingStrategy":"try-catch","validationCode":"// ensure COM init succeeded before use\nlet trash = Trash::new().map_err(|e| anyhow!(\"COM init failed: {e}\"))?;","typeGuard":"fn com_ready(r: &Result<Trash, std::io::Error>) -> bool { r.is_ok() }","tryCatchPattern":"match Trash::new() {\n    Ok(t) => t,\n    Err(e) => {\n        // RPC_E_CHANGED_MODE -> retry on a thread with correct apartment model\n        log::error!(\"COM init failed: {e}\");\n        return;\n    }\n}","preventionTips":["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."],"tags":["windows","com","threading","trash","rust"],"backgroundTag":"com-initialization-failed","analyzedSha":"5f901b886b14de1f17460b6e52e9de5d67f8aba9","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}