{"record":{"id":"cde711322ebc6d8d","repo":"gitbutlerapp/gitbutler","slug":"invalid-version-empty-string-usage-but-installe","errorCode":null,"errorMessage":"Invalid version: empty string. Usage: but-installer [version|nightly]","messagePattern":"Invalid version: empty string\\. Usage: but-installer \\[version\\|nightly\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/config.rs","lineNumber":47,"sourceCode":"/// - Contains at least one alphanumeric character\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Version(String);\n\nimpl Version {\n    /// Create a new Version from a string, validating the format.\n    ///\n    /// # Errors\n    /// Returns an error if the version string is invalid.\n    pub fn new(version: String) -> Result<Self> {\n        Self::validate(&version)?;\n        Ok(Version(version))\n    }\n\n    /// Validate a version string format\n    fn validate(version: &str) -> Result<()> {\n        // Reject empty strings\n        if version.is_empty() {\n            bail!(\"Invalid version: empty string. Usage: but-installer [version|nightly]\");\n        }\n\n        // Reject if it looks like a flag\n        if version.starts_with('-') {\n            bail!(\"Invalid version: {version}. Usage: but-installer [version|nightly]\");\n        }\n\n        // Only allow semver-compatible characters\n        if !version\n            .chars()\n            .all(|c| c.is_alphanumeric() || c == '.' || c == '-' || c == '+')\n        {\n            bail!(\n                \"Invalid version format: {version}. Version must contain only alphanumeric characters, dots, hyphens, and plus signs.\"\n            );\n        }\n\n        // Must contain at least one alphanumeric character","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/config.rs#L29-L65","documentation":"Thrown by but-installer's Version::validate (crates/but-installer/src/config.rs:47) when the version argument is an empty string. Version::new validates before constructing, so an empty input never becomes a Version value. In practice this almost always means a wrapper script passed an unset/empty shell variable ($1 missing) rather than a user literally typing nothing.","triggerScenarios":"Running `but-installer \"\"` ; a shell script invoking `but-installer $VERSION` with VERSION unset and the word-splitting leaving an empty arg; CI passing an empty matrix variable.","commonSituations":"Installer wrapper scripts that forward \"$1\" without a default; CI jobs with an optional version input that resolves to empty; typos in automation (env var name mismatch yields '').","solutions":["Pass an explicit version (`but-installer 1.2.3`) or the literal `nightly`","In scripts, default the variable: `but-installer \"${VERSION:-nightly}\"`","In CI, guard empty inputs before the call or set a fallback value on the variable"],"exampleFix":"# before\nbut-installer \"$VERSION\"   # VERSION unset -> empty string -> error\n\n# after\nbut-installer \"${VERSION:-nightly}\"","handlingStrategy":"validation","validationCode":"let version = std::env::args().nth(1).unwrap_or_default();\nif version.is_empty() {\n    eprintln!(\"no version given; defaulting to nightly\");\n    // or: std::process::exit(2);\n}\nlet v = Version::new(if version.is_empty() { \"nightly\".to_string() } else { version })?;","typeGuard":"fn non_empty_version(v: &str) -> bool { !v.is_empty() }","tryCatchPattern":"if let Err(err) = Version::new(version) {\n    if err.to_string().contains(\"empty string\") { eprintln!(\"usage: but-installer [version|nightly]\"); std::process::exit(2); }\n    return Err(err);\n}","preventionTips":["Default unset variables in scripts: but-installer \"${VERSION:-nightly}\"","Quote shell expansions so empty variables are visible instead of vanishing"],"tags":["but-installer","version","cli","validation","rust"],"backgroundTag":"invalid-version-string","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}