gitbutlerapp/gitbutler · info
skill format path components are never empty
Error message
skill format path components are never empty
What it means
`but skill install` copies embedded skill files into agent-format-specific directories. Each SkillFormat carries a static path_components slice; skills_parent_dir() splits off the last component and expects the slice to be non-empty. All formats are compile-time constants with at least one component (skill/mod.rs:66-87 and the SkillFormat table), so the panic fires only if a build registers a SkillFormat with an empty path_components.
Source
Thrown at crates/but/src/command/skill/mod.rs:136
Self {
name,
description: "Agent-specific global skill format",
availability: SkillFormatAvailability::GlobalOnly,
path_components,
}
}
/// Get the actual installation path given a base directory
fn get_install_path(&self, base_dir: &std::path::Path) -> PathBuf {
join_relative_path(base_dir, self.path_components)
}
/// The skills directory that holds this format's installation folder.
fn skills_parent_dir(&self, base_dir: &std::path::Path) -> PathBuf {
let (_, parent) = self
.path_components
.split_last()
.expect("skill format path components are never empty");
join_relative_path(base_dir, parent)
}
fn is_available_for(&self, global: bool) -> bool {
matches!(
(global, self.availability),
(_, SkillFormatAvailability::LocalAndGlobal)
| (false, SkillFormatAvailability::LocalOnly)
| (true, SkillFormatAvailability::GlobalOnly)
)
}
}
/// Install-path components (relative to a base directory) for a skill format,
/// selected by its display name and whether the install is global. This keeps
/// callers outside `but skill` — e.g. the `agent setup` wizard — installing to
/// the same locations that `but skill check`/install/update discover, instead of
/// duplicating (and drifting from) these paths.View on GitHub (pinned to 2497b8007a)
Solutions
- Give the new format at least one path component (its install folder relative to the skills base dir)
- Enforce it at construction: assert !path_components.is_empty() in SkillFormat::global/new so bad constants fail at startup or test time, not at install time
- Optionally degrade: treat empty components as 'install directly into base_dir' via unwrap_or rather than panicking
Example fix
// before — empty slice slips through to a render-time panic
const fn global(name: &'static str, path_components: &'static [&'static str]) -> Self { Self { name, path_components, .. } }
// after — fail at construction, not in skills_parent_dir
const fn global(name: &'static str, path_components: &'static [&'static str]) -> Self {
assert!(!path_components.is_empty(), "skill format needs an install path");
Self { name, path_components, .. }
} Defensive patterns
Strategy: validation
Validate before calling
// static sanity check for the format table, in a unit test
#[test]
fn skill_formats_have_paths() {
for format in SKILL_FORMATS {
assert!(!format.path_components.is_empty(), "format {} has no install path", format.name);
}
} Prevention
- Every SkillFormat must declare at least one install-path component; review new formats against the existing table
- When adding support for a new agent's skill layout, copy an existing entry (name + dir components) and adjust
- Assert non-emptiness at construction time so a bad constant fails at startup, not at `but skill install`
When it happens
Trigger: Running `but skill install` (or computing install paths) on a custom build where a newly added SkillFormat was defined with path_components: &[] (e.g. a newly supported agent format with a missing directory).
Common situations: Contributions adding a new agent skill format and forgetting the install directory; refactoring the static format table through a macro/helper that can emit empty slices.
Related errors
- target OID must exist when ahead calculation is enabled
- target OID must exist when merge check is enabled
- non-empty conflicts map contains a commit
- programs was just checked to be non-empty
- object for prefix exists
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/6415313f611c736f.
Report an issue: GitHub.