{"record":{"id":"43029c9faee49315","repo":"Hmbown/CodeWhale","slug":"install-source-must-not-be-empty","errorCode":null,"errorMessage":"install source must not be empty","messagePattern":"install source must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/plugins/install/mod.rs","lineNumber":110,"sourceCode":"    /// Local bundle directory (copied, never executed). Parsed from a plain\n    /// path or an explicit `path:<dir>` spec (the marker round-trip form).\n    LocalPath(PathBuf),\n    /// `github:owner/repo` or a direct `http(s)://…` tarball URL, downloaded\n    /// through the shared skill-install machinery. There is no registry\n    /// index in v1.\n    Remote(InstallSource),\n}\n\nimpl PluginInstallSource {\n    /// Parse a user-supplied spec.\n    ///\n    /// * `github:owner/repo`, `https://…` → [`PluginInstallSource::Remote`]\n    ///   (via [`InstallSource::parse`]; registry names are unreachable here)\n    /// * `path:<dir>` or any other value → [`PluginInstallSource::LocalPath`]\n    pub fn parse(spec: &str) -> Result<Self> {\n        let trimmed = spec.trim();\n        if trimmed.is_empty() {\n            bail!(\"install source must not be empty\");\n        }\n        if let Some(path) = trimmed.strip_prefix(\"path:\") {\n            return Self::local(path);\n        }\n        if trimmed.starts_with(\"github:\")\n            || trimmed.starts_with(\"https://\")\n            || trimmed.starts_with(\"http://\")\n        {\n            let source = InstallSource::parse(trimmed)?;\n            return match source {\n                InstallSource::GitHubRepo(_) | InstallSource::DirectUrl(_) => {\n                    remote_bundle_path(&source)?;\n                    Ok(Self::Remote(source))\n                }\n                InstallSource::Registry(_) => {\n                    unreachable!(\"prefixed specs never parse as a registry name\")\n                }\n            };","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/plugins/install/mod.rs#L92-L128","documentation":"PluginInstallSource::parse validates the install spec string before routing it to a remote or local source. An empty (or whitespace-only) spec cannot identify any install source, so parsing fails immediately with this error.","triggerScenarios":"Calling PluginInstallSource::parse(\"\") or parse(\"   \"), e.g. an unset plugin name/source field in a config file, an empty CLI argument, or a plugin entry missing its `source` key.","commonSituations":"Config TOML/JSON with `source = \"\"`; shell variable expansion producing an empty string (`install \"$PLUGIN_SRC\"` with PLUGIN_SRC unset); UI form submitted without choosing a source.","solutions":["Provide a non-empty install source: `github:owner/repo`, an `https://…` URL, or `path:<dir>`","Fix the config/CLI value that expands to an empty string","Guard the call site: trim and check `!spec.is_empty()` before invoking parse"],"exampleFix":"// before\nlet src = PluginInstallSource::parse(&spec)?;\n// after\nlet trimmed = spec.trim();\nanyhow::ensure!(!trimmed.is_empty(), \"plugin install source is required\");\nlet src = PluginInstallSource::parse(trimmed)?;","handlingStrategy":"validation","validationCode":"fn install_spec_ok(spec: &str) -> bool { !spec.trim().is_empty() }","typeGuard":null,"tryCatchPattern":"match PluginInstallSource::parse(spec) { Err(e) if e.to_string().contains(\"must not be empty\") => eprintln!(\"provide github:owner/repo, https://… or path:<dir>\"), other => other?, }","preventionTips":["Validate the source field in config schemas as non-empty","Quote shell variables: \"${PLUGIN_SRC:?unset}\"","Require the source input in UI forms before submit"],"tags":["validation","empty-input","plugins"],"backgroundTag":"empty-required-field","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}