{"record":{"id":"0d5fbf6c274d6288","repo":"sxyazi/yazi","slug":"not-a-file","errorCode":null,"errorMessage":"not a File","messagePattern":"not a File","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/file/data.rs","lineNumber":13,"sourceCode":"use anyhow::{anyhow, bail};\nuse yazi_macro::impl_data_any;\nuse yazi_shared::data::Data;\n\nuse crate::file::{File, Files};\n\nimpl_data_any!(File, from_into_lua = inherit);\n\nimpl TryFrom<Data> for File {\n\ttype Error = anyhow::Error;\n\n\tfn try_from(value: Data) -> Result<Self, Self::Error> {\n\t\tvalue.into_any::<Self>().ok_or_else(|| anyhow!(\"not a File\"))\n\t}\n}\n\nimpl TryFrom<&Data> for File {\n\ttype Error = anyhow::Error;\n\n\tfn try_from(value: &Data) -> Result<Self, Self::Error> {\n\t\tvalue.as_any::<Self>().cloned().ok_or_else(|| anyhow!(\"not a File\"))\n\t}\n}\n\nimpl TryFrom<Data> for Files {\n\ttype Error = anyhow::Error;\n\n\tfn try_from(value: Data) -> Result<Self, Self::Error> {\n\t\tlet Data::List(files) = value else { bail!(\"not a list of Files\") };\n\t\tfiles.into_iter().map(File::try_from).collect::<Result<_, _>>().map(Self)\n\t}","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/file/data.rs#L1-L31","documentation":"Data is yazi's dynamic typed value used at Lua/action boundaries. File::try_from(Data) unwraps the contained value with into_any::<File>(); if the Data holds any other type (string, table, different struct), the conversion fails with \"not a File\". It is a type mismatch at a dynamically-typed boundary, not a filesystem error.","triggerScenarios":"Passing a Data wrapping something else where a File is required: extracting plugin/action arguments, decoding event payloads, or feeding results of generic Data-valued APIs into File::try_from.","commonSituations":"Lua-side code handing untyped values into Rust helpers; payload shape drift after type changes; plugins re-wrapping File fields into plain tables.","solutions":["Pass the actual File value through (e.g. from a Folder's entries) instead of re-wrapping other data","Branch on the contained type before converting (as_any::<File>()) and give a precise error","On the Lua side, keep File userdata intact rather than converting to tables"],"exampleFix":"// before\nlet f = File::try_from(data)?; // data actually holds a Strand\n\n// after\nlet Some(f) = data.into_any::<File>() else {\n    bail!(\"expected a File, got a different type\");\n};","handlingStrategy":"type-guard","validationCode":"// Check the contained type before consuming:\nensure!(data.as_any::<File>().is_some(), \"expected a File\");\nlet f = File::try_from(data)?;","typeGuard":"fn is_file(d: &Data) -> bool { d.as_any::<File>().is_some() }","tryCatchPattern":"match data.into_any::<File>() {\n    Some(f) => f,\n    None => bail!(\"expected a File, got a different Data type\"),\n}","preventionTips":["Narrow with as_any before converting at dynamic boundaries","Keep File values flowing as File, not re-wrapped in other Data","Validate types at the Lua boundary where everything is dynamic"],"tags":["data","lua","types","conversion"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}