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

  1. Check that the path is a regular file before offering/performing line discard; otherwise use whole-file restore or deletion.
  2. If the path is a symlink, resolve or skip it — line-level operations on symlink targets are not supported.
  3. 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

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


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)