gitbutlerapp/gitbutler · error
Cannot discard lines in
Error message
Cannot discard lines in '{}' - invalid type What it means
Thrown when discarding selected lines requires rewriting the worktree file, but the path on disk is not a regular file (symlink, directory, missing, socket, etc.), detected via gix's Metadata::from_path_no_follow and md.is_file(). Hunk discard only works on regular files, so anything else is rejected.
Solutions
- Check that the path is a regular file before offering/performing line discard; otherwise use whole-file restore or deletion.
- If the path is a symlink, resolve or skip it — line-level operations on symlink targets are not supported.
- If the file was deleted, restore the whole file instead of discarding hunks.
Example fix
// before
hunk::discard_lines(wt_change, hunks)?;
// after
let md = std::fs::metadata(path)?;
if md.is_file() {
hunk::discard_lines(wt_change, hunks)?;
} else {
whole_file_restore(wt_change)?; // or skip
} Defensive patterns
Strategy: validation
Validate before calling
fn is_regular_file(p: &std::path::Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)
} Try / catch
// narrow by message when preflight is skipped
match res {
Err(e) if e.to_string().contains("invalid type") => whole_file_or_skip(change)?,
other => other?,
} Prevention
- Check symlink_metadata().is_file() before offering line-level discard
- Skip or whole-file-restore symlinks and directories
- Refresh the file listing after external tools may have changed the worktree
When it happens
Trigger: Calling hunk-based restore_state_to_worktree for a path whose filesystem entry is a symlink, directory, device node, or does not exist as a regular file — e.g. the index says it was a blob but the worktree replaced it with a symlink or the file was deleted.
Common situations: Repo contains symlinks (or gained them via typechange); build tools replaced a file with a symlink; worktree checked out on a filesystem that materialized paths differently; user deleted the file while the UI still offered line-level discard.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Could not delete branch
- ' ' already exists
- The repository at has no .git directory. GitButler requires…
- Aborting due to empty branch name
- Ad-hoc (single-branch) branch moves are not supported…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/0ca1e8f46b2fe173.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-workspace/src/tree_manipulation/discard_worktree_changes.rs:663
true
}
});
if subtractions.is_empty() {
hunks_to_keep_with_splits.push(hunk_to_split);
} else {
hunks_to_keep_with_splits.extend(subtract_hunks(hunk_to_split, subtractions)?);
}
}
hunks_to_keep = hunks_to_keep_with_splits;
}
let old = previous_state.id.attach(repo).object()?.detach().data;
let mut new = repo.empty_reusable_buffer();
let rela_path = wt_change.path.as_bstr();
let worktree_path = path_check.verified_path_allow_nonexisting(rela_path)?;
let md = gix::index::fs::Metadata::from_path_no_follow(&worktree_path)?;
if !md.is_file() {
bail!(
"Cannot discard lines in '{}' - invalid type",
worktree_path.display()
);
}
worktree_file_to_git_in_buf(&mut new, &md, rela_path, &worktree_path, pipeline, index)?;
let base_with_patches = apply_hunks(old.as_bstr(), new.as_bstr(), &hunks_to_keep)?;
let to_worktree = pipeline.convert_to_worktree(
&base_with_patches,
rela_path,
gix::filter::plumbing::pipeline::convert::to_worktree::Options {
can_delay: Delay::Forbid,
..Default::default()
},
)?;
match to_worktree {
ToWorktreeOutcome::Unchanged(buf) => {View on GitHub (pinned to 58e5313667)