{"record":{"id":"5357687f35688a4e","repo":"sxyazi/yazi","slug":"invalid-op-in-updatefilesform","errorCode":null,"errorMessage":"Invalid 'op' in UpdateFilesForm","messagePattern":"Invalid 'op' in UpdateFilesForm","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"yazi-parser/src/mgr/update_files.rs","lineNumber":17,"sourceCode":"use anyhow::bail;\nuse mlua::{FromLua, IntoLua, Lua, Table, Value};\nuse yazi_fs::FilesOp;\nuse yazi_shared::{event::ActionCow, id::Id};\n\n#[derive(Debug)]\npub struct UpdateFilesForm {\n\tpub op:   FilesOp,\n\tpub tabs: Vec<Id>,\n}\n\nimpl TryFrom<ActionCow> for UpdateFilesForm {\n\ttype Error = anyhow::Error;\n\n\tfn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {\n\t\tlet Some(op) = a.take_any(\"op\") else {\n\t\t\tbail!(\"Invalid 'op' in UpdateFilesForm\");\n\t\t};\n\n\t\tOk(Self { op, tabs: vec![] })\n\t}\n}\n\nimpl From<FilesOp> for UpdateFilesForm {\n\tfn from(op: FilesOp) -> Self { Self { op, tabs: vec![] } }\n}\n\nimpl FromLua for UpdateFilesForm {\n\tfn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {\n\t\tlet t = Table::from_lua(value, lua)?;\n\n\t\tOk(Self { op: t.raw_get(\"op\")?, tabs: t.raw_get(\"tabs\")? })\n\t}\n}\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/sxyazi/yazi/blob/5f901b886b14de1f17460b6e52e9de5d67f8aba9/yazi-parser/src/mgr/update_files.rs#L1-L35","documentation":"UpdateFilesForm carries a file-update operation payload and the `op` field (the update operation data) is mandatory. The TryFrom<ActionCow> implementation takes `op` from the action and bails when it is missing, so an update_files action without operation data cannot be constructed.","triggerScenarios":"Emitting a `update_files` action without an `op` payload key, e.g. `ya.emit('update_files', { tabs = ... })` with no `op`, or `Manager:update_files({})`.","commonSituations":"Plugin code forwarding file-update events after dropping or renaming the payload fields; hand-built IPC/remote-control messages missing the op entry.","solutions":["Always include the `op` payload key (the update-op data) when emitting update_files","Re-read the changed file entries and rebuild the op payload rather than forwarding an empty table","Log/inspect the action payload before emit to confirm `op` is present"],"exampleFix":"// before\nya.emit('update_files', { tabs = { tab.id } })\n// after\nya.emit('update_files', { op = op, tabs = { tab.id } })","handlingStrategy":"validation","validationCode":"assert(op ~= nil, \"update_files requires an 'op' payload\")\nya.emit('update_files', { op = op, tabs = tabs })","typeGuard":null,"tryCatchPattern":"-- Rust\nmatch UpdateFilesForm::try_from(action) {\n  Ok(form) => handle(form),\n  Err(e) => tracing::warn!(\"update_files skipped: {e}\"),\n}","preventionTips":["Never forward update_files actions after destructuring the payload","Keep op and tabs together when copying the action payload","Log the payload before emit during plugin development"],"tags":["plugin-api","validation","action-payload"],"backgroundTag":"missing-required-action-field","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"}