gitbutlerapp/gitbutler · error
BUG: It should not be possible to omit sources
Error message
BUG: It should not be possible to omit sources
What it means
`resolve_sources` in but's legacy `move` command matches on which source kinds were detected (committed changes / untracked changes / branches). The `(None, None, None)` arm panics with 'BUG: It should not be possible to omit sources' because the argument parsing layer is expected to reject an empty `<SOURCES>` earlier, so resolution should never see zero sources. Hitting it means an empty or fully-unrecognized SOURCES argument slipped past that earlier validation.
Source
Thrown at crates/but/src/command/legacy/move.rs:868
}
// It doesn't appear as if we need to sort DiffSpecs when they're resolved on a file
// level. For the future hunk level DiffSpecs we may need to, however.
let changes = NonEmpty::from_vec(builder.into_diff_specs())
.expect("BUG: Cannot possibly not have any changes here");
Ok(ResolvedSources::CommittedChanges((source_commit, changes)))
}
(None, None, Some(branches)) => {
if !branches.tail.is_empty() {
Err(bad_input("Branches can only be moved one at a time")
.arg_name("<SOURCES>")
.into())
} else {
Ok(ResolvedSources::Branch(branches.head))
}
}
(None, None, None) => panic!("BUG: It should not be possible to omit sources"),
(_, _, _) => Err(bad_input("Mixing source types is not allowed")
.hint("You can only move one kind of source (e.g. commits) at a time")
.arg_name("<SOURCES>")
.into()),
}
}
pub fn run(
ctx: &mut Context,
meta: &mut impl RefMetadata,
perm: &mut RepoExclusive,
move_op: MoveOperation,
) -> anyhow::Result<(MoveOutcome, WorkspaceState)> {
let snapshot_details = match &move_op {
MoveOperation::CommitsRelativeTo(_) | MoveOperation::CommitsToNewBranch(_) => {
SnapshotDetails::new(OperationKind::MoveCommit)
}
MoveOperation::ChangesRelativeTo(_) | MoveOperation::ChangesToNewBranch(_) => {View on GitHub (pinned to caf1f223d3)
Solutions
- Pass at least one valid source (commit-ish, branch name, or untracked path) in `<SOURCES>`.
- If you hit it from code, add a `bad_input` check that errors when resolved sources are empty instead of dispatching.
- Check for trailing whitespace/empty args in the wrapper script producing the command line.
Example fix
// before
let sources = resolve_sources(args)?; // panics on (None, None, None)
// after
let sources = resolve_sources(args)?;
if sources.is_empty() {
return Err(bad_input("At least one <SOURCES> entry is required")
.arg_name("<SOURCES>")
.into());
} Defensive patterns
Strategy: validation
Validate before calling
// wrapper guard before invoking the legacy move path
fn ensure_sources_present(resolved: &ResolvedSources) -> anyhow::Result<()> {
if resolved.is_empty() {
return Err(bad_input("At least one <SOURCES> entry is required")
.arg_name("<SOURCES>")
.into());
}
Ok(())
} Try / catch
let sources = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| resolve_sources(&args)))
.unwrap_or_else(|_| panic!("<SOURCES> resolved to nothing — pass a commit, branch, or untracked path")); Prevention
- Pass non-empty SOURCES arguments; check shell variables for empty expansion before invoking the CLI.
- Keep parser-level rejection of empty SOURCES intact when touching argument parsing.
- For programmatic callers, validate resolved source counts before dispatching the move operation.
When it happens
Trigger: Running the legacy move command with a SOURCES argument that parses to zero recognized items (empty string segments, or revision specs that resolve to nothing); programmatic invocation of the resolve path with empty input.
Common situations: Scripts passing an unset/empty shell variable as SOURCES; a CLI parser regression that stops rejecting empty SOURCES; new frontends calling the legacy move internals directly.
Related errors
- {} target value is required
- target kind is required when target value is provided
- Invalid source: expected an uncommitted file or branch
- valid hex prefix
- object for prefix exists
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/b9e84dc1891cbec6.
Report an issue: GitHub.