{"record":{"id":"4dd5397e0b11368b","repo":"gitbutlerapp/gitbutler","slug":"failed-to-create-blank-commit-in-stack-stack-id","errorCode":null,"errorMessage":"Failed to create blank commit in stack: {stack_id:?}","messagePattern":"Failed to create blank commit in stack: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-api/src/legacy/absorb.rs","lineNumber":459,"sourceCode":"        let branch = find_target_branch(&stack_details, branch_ref)\n            .ok_or_else(|| anyhow::anyhow!(\"Stack has no branches\"))?;\n        commit_insert_blank_only_impl(\n            ctx,\n            RelativeTo::Reference(branch.reference.clone()),\n            InsertSide::Below,\n            DryRun::No,\n            perm,\n        )?;\n\n        // Fetch again to get the newly created commit\n        let stack_details = crate::legacy::workspace::stack_details(ctx, Some(stack_id))?;\n        if let Some(branch) = find_target_branch(&stack_details, branch_ref)\n            && let Some(commit) = branch.commits.first()\n        {\n            return Ok((stack_id, commit.id, AbsorptionReason::StackAssignment));\n        }\n\n        anyhow::bail!(\"Failed to create blank commit in stack: {stack_id:?}\");\n    }\n\n    // Priority 3: If no assignment, find the topmost commit of the leftmost lane\n    let stacks = crate::legacy::workspace::stacks(ctx, None)?;\n    if let Some(stack) = stacks.first()\n        && let Some(stack_id) = stack.id\n    {\n        let stack_details = crate::legacy::workspace::stack_details(ctx, Some(stack_id))?;\n        if let Some(branch) = stack_details.branch_details.first()\n            && let Some(commit) = branch.commits.first()\n        {\n            return Ok((stack_id, commit.id, AbsorptionReason::DefaultStack));\n        }\n\n        // If the first stack has no commits, create a blank commit first\n        let branch = stack_details\n            .branch_details\n            .first()","sourceCodeStart":441,"sourceCodeEnd":477,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-api/src/legacy/absorb.rs#L441-L477","documentation":"Priority 2 fallback: the assigned stack's target branch has no commits, so a blank commit is inserted below the branch reference via commit_insert_blank_only_impl() and stack details are re-fetched. If the re-fetch still shows no commits on that branch, the insert did not materialize in the workspace view and absorption bails.","triggerScenarios":"The blank-commit insert returned Ok but the refetched stack details still report an empty branch: stale metadata cache, the branch reference moved concurrently, or another writer updated the workspace between insert and re-fetch.","commonSituations":"Concurrent GitButler operations (push, branch update) racing absorb; a second process (CLI while the GUI is open) mutating the same project; metadata cache invalidation gaps after insert.","solutions":["Retry the absorb once after reloading the workspace view","Verify in the stacks UI that the blank commit actually appeared; if it did, a plain retry succeeds","Close competing GitButler/git processes for the same project and retry","If reproducible, capture logs — insert Ok but empty refetch indicates a cache/invalidation bug worth reporting"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let details = workspace_stack_details(ctx, stack_id)?;\nlet branch_has_commits = details.branch_details.iter()\n    .find(|b| Some(&b.reference) == branch_ref.as_ref())\n    .or_else(|| details.branch_details.first())\n    .is_some_and(|b| !b.commits.is_empty());\nif !branch_has_commits {\n    // blank-commit path will run; be ready to reload and retry once\n}","typeGuard":null,"tryCatchPattern":"let mut last_err = None;\nfor attempt in 0..2 {\n    match absorption_plan_with_perm(ctx, target.clone(), perm) {\n        Ok(plan) => return Ok(plan),\n        Err(e) if attempt == 0 && e.to_string().contains(\"Failed to create blank commit\") => {\n            reload_workspace(ctx); // drop caches, then retry once\n            last_err = Some(e);\n        }\n        Err(e) => return Err(e),\n    }\n}\nreturn Err(last_err.unwrap());","preventionTips":["Run only one mutating GitButler surface (GUI or CLI) per project at a time","Reload workspace state before retrying absorb after any insert","Report repeat occurrences with tracing logs of the insert call"],"tags":["git","absorb","commit-insert","race-condition","caching"],"backgroundTag":"state-refresh-mismatch","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}