{"record":{"id":"0ca1e8f46b2fe173","repo":"gitbutlerapp/gitbutler","slug":"cannot-discard-lines-in-invalid-type","errorCode":null,"errorMessage":"Cannot discard lines in '{}' - invalid type","messagePattern":"Cannot discard lines in '(.+?)' - invalid type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/tree_manipulation/discard_worktree_changes.rs","lineNumber":663,"sourceCode":"                        true\n                    }\n                });\n                if subtractions.is_empty() {\n                    hunks_to_keep_with_splits.push(hunk_to_split);\n                } else {\n                    hunks_to_keep_with_splits.extend(subtract_hunks(hunk_to_split, subtractions)?);\n                }\n            }\n            hunks_to_keep = hunks_to_keep_with_splits;\n        }\n\n        let old = previous_state.id.attach(repo).object()?.detach().data;\n        let mut new = repo.empty_reusable_buffer();\n        let rela_path = wt_change.path.as_bstr();\n        let worktree_path = path_check.verified_path_allow_nonexisting(rela_path)?;\n        let md = gix::index::fs::Metadata::from_path_no_follow(&worktree_path)?;\n        if !md.is_file() {\n            bail!(\n                \"Cannot discard lines in '{}' - invalid type\",\n                worktree_path.display()\n            );\n        }\n        worktree_file_to_git_in_buf(&mut new, &md, rela_path, &worktree_path, pipeline, index)?;\n\n        let base_with_patches = apply_hunks(old.as_bstr(), new.as_bstr(), &hunks_to_keep)?;\n\n        let to_worktree = pipeline.convert_to_worktree(\n            &base_with_patches,\n            rela_path,\n            gix::filter::plumbing::pipeline::convert::to_worktree::Options {\n                can_delay: Delay::Forbid,\n                ..Default::default()\n            },\n        )?;\n        match to_worktree {\n            ToWorktreeOutcome::Unchanged(buf) => {","sourceCodeStart":645,"sourceCodeEnd":681,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-workspace/src/tree_manipulation/discard_worktree_changes.rs#L645-L681","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nhunk::discard_lines(wt_change, hunks)?;\n\n// after\nlet md = std::fs::metadata(path)?;\nif md.is_file() {\n    hunk::discard_lines(wt_change, hunks)?;\n} else {\n    whole_file_restore(wt_change)?; // or skip\n}","handlingStrategy":"validation","validationCode":"fn is_regular_file(p: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"// narrow by message when preflight is skipped\nmatch res {\n    Err(e) if e.to_string().contains(\"invalid type\") => whole_file_or_skip(change)?,\n    other => other?,\n}","preventionTips":["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"],"tags":["git","filesystem","path-type"],"backgroundTag":"type-mismatch","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}