{"record":{"id":"1e2d712d74a379f6","repo":"gitbutlerapp/gitbutler","slug":"cannot-unapply-workspace-reference-without-sw","errorCode":null,"errorMessage":"Cannot unapply workspace reference '{}' without switching away from it","messagePattern":"Cannot unapply workspace reference '(.+?)' without switching away from it","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-workspace/src/branch/unapply.rs","lineNumber":554,"sourceCode":"\n    /// Unapply the managed workspace reference itself.\n    ///\n    /// - Run before normal branch removal because the workspace ref is a container, not a stack segment.\n    /// - Reject dispositions that keep the workspace ref because unapplying it requires switching away.\n    /// - Pick a named checkout target from the current projection.\n    /// - Reject GitButler-conflicted target commits with a ref-aware error.\n    /// - Safely checkout the target commit, then switch `HEAD` to the target ref.\n    /// - Optionally delete the managed workspace ref and metadata.\n    /// - Retraverse from the target ref so the returned workspace matches the new `HEAD`.\n    fn unapply_workspace_reference(\n        ws: &but_graph::Workspace,\n        repo: &gix::Repository,\n        meta: &mut impl RefMetadata,\n        workspace_ref_name: &FullNameRef,\n        disposition: WorkspaceDisposition,\n    ) -> anyhow::Result<Outcome<'static>> {\n        if !disposition.may_switch_away_from_workspace() {\n            bail!(\n                \"Cannot unapply workspace reference '{}' without switching away from it\",\n                workspace_ref_name.shorten()\n            );\n        }\n\n        let ref_to_checkout = ref_to_checkout_after_workspace_unapply(ws)?;\n        safe_checkout_ref_to_checkout(\n            repo,\n            &ref_to_checkout,\n            but_core::worktree::checkout::Options {\n                skip_head_update: true,\n                ..Default::default()\n            },\n        )?;\n\n        let workspace_ref_expected = ws\n            .tip_commit()\n            .context(\"BUG: unborn should be impossible here\")?","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-workspace/src/branch/unapply.rs#L536-L572","documentation":"unapply_workspace_reference must check out another ref to move HEAD away from the workspace ref it is removing, but the passed WorkspaceDisposition does not allow switching away. Only the PreventUnnecessaryWorkspaceReferences variants set may_switch_away_from_workspace() to true; the default KeepWorkspaceCommit (and KeepWorkspaceReference) forbid it. Pass a disposition that permits switching when you actually want the workspace ref gone.","triggerScenarios":"Calling unapply on the workspace's own reference with Options { workspace_disposition: KeepWorkspaceCommit } or KeepWorkspaceReference — dispositions that require staying on the workspace ref.","commonSituations":"Default-constructed Options (KeepWorkspaceCommit is the #[default]) used on the workspace-reference unapply path; callers copying branch-unapply options into workspace-ref unapply.","solutions":["Pass WorkspaceDisposition::PreventUnnecessaryWorkspaceReferences (or ...KeepWorkspaceCommit) so unapply may switch HEAD away and delete the workspace ref.","If you must keep the workspace ref checked out, do not unapply the workspace reference itself — unapply inner branches instead.","Check disposition.may_switch_away_from_workspace() semantics before wiring UI actions."],"exampleFix":"// before\nlet opts = Options::default(); // KeepWorkspaceCommit\nunapply(repo, meta, &ws, ws_ref, opts)?;\n\n// after\nlet opts = Options {\n    workspace_disposition: WorkspaceDisposition::PreventUnnecessaryWorkspaceReferences,\n};\nunapply(repo, meta, &ws, ws_ref, opts)?;","handlingStrategy":"validation","validationCode":"use but_workspace::branch::unapply::WorkspaceDisposition;\nlet disposition = WorkspaceDisposition::PreventUnnecessaryWorkspaceReferences;\nif !matches!(disposition, WorkspaceDisposition::KeepWorkspaceCommit | WorkspaceDisposition::KeepWorkspaceReference) {\n    // disposition may switch away from the workspace ref: safe to unapply it\n}","typeGuard":null,"tryCatchPattern":"match unapply(repo, meta, &ws, ws_ref, opts) {\n    Err(err) if err.to_string().contains(\"without switching away from it\") => {\n        let opts = Options {\n            workspace_disposition: WorkspaceDisposition::PreventUnnecessaryWorkspaceReferences,\n        };\n        unapply(repo, meta, &ws, ws_ref, opts)\n    }\n    other => other,\n}","preventionTips":["Never use Options::default() when unapplying the workspace reference itself.","Pick the disposition based on intent: keep the ref vs dissolve the workspace.","Document the PreventUnnecessaryWorkspaceReferences variants in wrapper layers."],"tags":["gitbutler","unapply","workspace-ref","disposition","rust"],"backgroundTag":"workspace-disposition-conflict","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}