gitbutlerapp/gitbutler · error
Unknown app suffix '{value}', expected one of: dev, nightly,
Error message
Unknown app suffix '{value}', expected one of: dev, nightly, release What it means
`AppChannel::from_str` rejects any value outside the accepted set: `nightly`, `release`/`production`/`prod`, and `dev`/`development` (case-sensitive). It exists so channel identifiers parsed from CLI args, env vars, or config reject unknown suffixes instead of silently defaulting. The error lists the canonical accepted values.
Source
Thrown at crates/but-path/src/lib.rs:339
new_window: bool,
) -> anyhow::Result<url::Url> {
let mut url = url::Url::parse(&format!("{scheme}://open"))?;
url.query_pairs_mut()
.append_pair("path", &possibly_project_dir.to_string_lossy())
.append_pair("t", ×tamp.to_string())
.append_pair("new_window", if new_window { "1" } else { "0" });
Ok(url)
}
impl std::str::FromStr for AppChannel {
type Err = anyhow::Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"nightly" => Ok(AppChannel::Nightly),
"release" | "production" | "prod" => Ok(AppChannel::Release),
"dev" | "development" => Ok(AppChannel::Dev),
_ => Err(anyhow::anyhow!(
"Unknown app suffix '{value}', expected one of: dev, nightly, release"
)),
}
}
}
fn clean_env_vars<'a, 'b>(
var_names: &'a [&'b str],
) -> impl Iterator<Item = (&'b str, String)> + 'a {
var_names
.iter()
.filter_map(|name| env::var(name).map(|value| (*name, value)).ok())
.map(|(name, value)| {
(
name,
value
.split(':')
.filter(|path| !path.contains("appimage-run") && !path.contains("/tmp/.mount"))View on GitHub (pinned to caf1f223d3)
Solutions
- Use one of: dev, nightly, release (aliases: development, production, prod)
- Trim and lowercase the input before parsing
- If unknown channels should fall back, match explicitly first and default to `AppChannel::Release` instead of parsing blindly
Example fix
// before
let channel: AppChannel = arg.parse()?; // Unknown app suffix 'stable'
// after
let channel = match arg.trim().to_ascii_lowercase().as_str() {
"nightly" => AppChannel::Nightly,
"dev" | "development" => AppChannel::Dev,
"release" | "production" | "prod" | _ => AppChannel::Release,
}; Defensive patterns
Strategy: validation
Validate before calling
const VALID_CHANNELS: &[&str] = &["dev", "development", "nightly", "release", "production", "prod"];
anyhow::ensure!(VALID_CHANNELS.contains(&value.trim()), "invalid channel {value}");
let channel: AppChannel = value.trim().parse()?; Type guard
fn is_valid_app_channel(value: &str) -> bool {
matches!(
value.trim(),
"dev" | "development" | "nightly" | "release" | "production" | "prod"
)
} Prevention
- Trim and lowercase channel strings from env/CLI before parsing
- Keep the accepted list in one shared constant so producers and the parser cannot drift
- Reject unknown channels at config load with a message listing valid values
When it happens
Trigger: Parsing "stable", "beta", "Release" (wrong case), or "production " (whitespace) from `--channel`-style args, environment variables, or serialized config into `AppChannel`.
Common situations: Scripts passing marketing channel names ("stable") that don't map to build channels; config written for a newer/older version with renamed channels; casing or trailing-newline mistakes when piping values from files.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid section for global key: {key}
- line {line_number}: pick does not accept a message clause
- line {line_number}: pick requires exactly one commit
- line {line_number}: merge does not accept a message clause
- line {line_number}: merge requires exactly one commit
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/724ba35d45eaea62.
Report an issue: GitHub.