{"record":{"id":"aed8472c1c197e35","repo":"sxyazi/yazi","slug":"plugin-name-plugin-must-be-in-kebab-case","errorCode":null,"errorMessage":"Plugin name `{plugin}` must be in kebab-case","messagePattern":"Plugin name `(.+?)` must be in kebab-case","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"yazi-runner/src/loader/loader.rs","lineNumber":192,"sourceCode":"\n\tpub fn compatible_or_error(name: &str, chunk: &Chunk) -> Result<()> {\n\t\tif chunk.compatible() {\n\t\t\treturn Ok(());\n\t\t}\n\n\t\tbail!(\n\t\t\t\"Plugin `{name}` requires at least Yazi {}, but your current version is Yazi {}.\",\n\t\t\tchunk.since,\n\t\t\tyazi_version::version_long()\n\t\t);\n\t}\n\n\tfn explode_name_parts(name: &str) -> anyhow::Result<(&str, &str, &str)> {\n\t\tlet name = name.strip_suffix(\".main\").unwrap_or(name);\n\t\tlet (plugin, entry) =\n\t\t\tif let Some((a, b)) = name.split_once(\".\") { (a, b) } else { (name, \"main\") };\n\n\t\tensure!(plugin.as_bytes().kebab_cased(), \"Plugin name `{plugin}` must be in kebab-case\");\n\t\tensure!(entry.as_bytes().kebab_cased(), \"Entry name `{entry}` must be in kebab-case\");\n\t\tOk((name, plugin, entry))\n\t}\n}\n","sourceCodeStart":174,"sourceCodeEnd":197,"githubUrl":"https://github.com/sxyazi/yazi/blob/8ebf930f1796ae2076b7d6b0c5e93a1002c18134/yazi-runner/src/loader/loader.rs#L174-L197","documentation":"Loader::explode_name_parts parses a plugin name like `plugin.entry` (with `.main` defaulting the entry) and validates that the plugin portion is kebab-case (lowercase words separated by hyphens). Plugin names become filesystem module paths and Lua identifiers, so naming must be normalized; anything else is rejected with this message.","triggerScenarios":"Loading or resolving a plugin whose name segment before the first dot (or whole name when no dot) is not kebab-case, e.g. `MyPlugin`, `my_plugin`, `myPlugin.main`, or containing uppercase/underscores/spaces.","commonSituations":"Typos in a plugin name passed to plugin loader calls, referencing a plugin directory created with CamelCase or snake_case naming, or installing a third-party plugin whose directory name violates the convention.","solutions":["Rename the plugin directory/config entry to kebab-case (e.g., MyPlugin -> my-plugin)","If invoking by name, correct the string to the plugin's kebab-case name","Check for underscores vs hyphens in the name"],"exampleFix":"// before\nya.plugin(\"MyPlugin.main\")\n// after\nya.plugin(\"my-plugin.main\")","handlingStrategy":"validation","validationCode":"fn is_kebab(s: &str) -> bool {\n    !s.is_empty()\n        && s.bytes().all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'-')\n        && !s.starts_with('-') && !s.ends_with('-')\n}\nassert!(is_kebab(\"my-plugin\"));","typeGuard":"fn valid_plugin_name(name: &str) -> Option<(&str, &str)> {\n    let (p, e) = name.split_once('.').unwrap_or((name, \"main\"));\n    is_kebab(p).then_some((p, e))\n}","tryCatchPattern":"match Loader::load(name) {\n    Ok(p) => p,\n    Err(e) => eprintln!(\"plugin load failed: {e}\") // message names the offending `plugin`\n}","preventionTips":["Name plugin directories in lowercase kebab-case","Use hyphens, never underscores or camelCase, for plugin names","Check the error message: it echoes the offending name verbatim"],"tags":["plugin","naming","validation","kebab-case"],"backgroundTag":"invalid-naming-convention","analyzedSha":"8ebf930f1796ae2076b7d6b0c5e93a1002c18134","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}