{"record":{"id":"e494790f9c068288","repo":"gitbutlerapp/gitbutler","slug":"commit-is-not-in-the-applied-workspace","errorCode":null,"errorMessage":"Commit {} is not in the applied workspace","messagePattern":"Commit (.+?) is not in the applied workspace","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-comments/src/lib.rs","lineNumber":131,"sourceCode":"\n/// Create a new comment anchored to a line in a diff.\n///\n/// The anchor must point at a line that exists in the current diff — the uncommitted worktree\n/// diff of `path`, or the first-parent diff of the workspace commit with `commit_change_id` —\n/// otherwise an error is returned. The anchored line's content (and its neighbours) is\n/// snapshotted so the comment can be re-located when the diff drifts.\npub fn create_comment(\n    repo: &gix::Repository,\n    workspace: &but_graph::Workspace,\n    store: &CommentStore,\n    comment: NewComment,\n    context_lines: u32,\n    now_ms: i64,\n) -> anyhow::Result<DiffComment> {\n    let scope = anchor_scope_display(&comment.commit_change_id, &comment.path);\n    let mut diffs = ScopeDiffs::new(repo, workspace, context_lines);\n    let Some(anchor) = diffs.file(comment.commit_change_id.as_deref(), &comment.path)? else {\n        bail!(\n            \"Commit {} is not in the applied workspace\",\n            comment.commit_change_id.as_deref().unwrap_or_default()\n        );\n    };\n    let file = match anchor {\n        FileAnchor::Lines(lines) => lines,\n        FileAnchor::Gone => bail!(\"Nothing to anchor a comment to in {scope}\"),\n        FileAnchor::Unanchorable => {\n            bail!(\"Cannot comment on {scope}: the diff is binary or too large\")\n        }\n    };\n    let line = file\n        .line_at(comment.side, comment.line_number)\n        .with_context(|| {\n            format!(\n                \"No line {} on the {} side in {scope}\",\n                comment.line_number,\n                comment.side.as_str(),","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-comments/src/lib.rs#L113-L149","documentation":"create_comment() calls ScopeDiffs::file(commit_change_id, path) to locate the file to anchor to; when it returns None, the commit identified by that change-id is not part of the applied workspace the diff was computed from, and the comment cannot be located. The change-id (not a raw sha) is the workspace's stable handle for a commit, so this specifically means 'that change is not applied right now'.","triggerScenarios":"Creating a diff comment for a commit that was unapplied/archived from the workspace, whose change-id went stale after a rebase rewrote the commit, or when the caller builds the request from a UI state older than the current workspace.","commonSituations":"User opens a diff, the workspace is reorganized (unapply/rebase/order change) in another window or by a teammate's sync, then the user hits 'comment'; automation replaying stored change-ids after history rewrites.","solutions":["Refresh the workspace and re-create the comment against the commit's current change-id","Re-apply the unapplied commit so it is part of the applied workspace, then comment","If the commit was rewritten, look up its new change-id from the current workspace before commenting","Guard callers to re-resolve change-ids right before create_comment instead of caching them"],"exampleFix":"// before: change-id captured earlier, may be unapplied now\nbut_comments::create_comment(&repo, &workspace, &store, comment, 3, 0, now)?;\n\n// after: re-resolve against the live workspace first\nlet applied: Vec<_> = workspace.applied_change_ids();\nanyhow::ensure!(applied.contains(&comment.commit_change_id), \"commit no longer applied\");\nbut_comments::create_comment(&repo, &workspace, &store, comment, 3, 0, now)?;","handlingStrategy":"validation","validationCode":"// confirm the change-id is currently applied before creating the comment\nlet applied: Vec<_> = workspace.applied_commits().iter().map(|c| c.change_id().to_owned()).collect();\nanyhow::ensure!(\n    comment.commit_change_id.as_ref().is_some_and(|id| applied.contains(id)),\n    \"commit no longer in the applied workspace\"\n);","typeGuard":null,"tryCatchPattern":"match but_comments::create_comment(&repo, &ws, &store, comment.clone(), 3, 0, now) {\n    Err(e) if e.to_string().contains(\"not in the applied workspace\") =>\n        Err(anyhow!(\"comment target drifted — refresh and retry\")),\n    r => r?,\n}","preventionTips":["Re-resolve change-ids from the live workspace right before create_comment, never cache across workspace mutations","Disable comment submission while a workspace update/rebase is in flight","Return the fresh workspace version to clients so they can detect drift"],"tags":["comments","workspace","diff","change-id"],"backgroundTag":"stale-commit-reference","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}