{"record":{"id":"824e7a9ad2a44273","repo":"gitbutlerapp/gitbutler","slug":"expected-to-be-in-edit-mode","errorCode":null,"errorMessage":"Expected to be in edit mode","messagePattern":"Expected to be in edit mode","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gitbutler-operating-modes/src/lib.rs","lineNumber":223,"sourceCode":"    Ok(operating_mode(ctx, perm)? == OperatingMode::OpenWorkspace)\n}\n\npub fn ensure_open_workspace_mode(ctx: &Context, perm: &RepoShared) -> Result<()> {\n    if in_open_workspace_mode(ctx, perm)? {\n        Ok(())\n    } else {\n        bail!(\"Expected to be in open workspace mode\")\n    }\n}\n\npub fn in_edit_mode(ctx: &Context, perm: &RepoShared) -> Result<bool> {\n    Ok(matches!(operating_mode(ctx, perm)?, OperatingMode::Edit(_)))\n}\n\npub fn ensure_edit_mode(ctx: &Context, perm: &RepoShared) -> Result<EditModeMetadata> {\n    match operating_mode(ctx, perm)? {\n        OperatingMode::Edit(edit_mode_metadata) => Ok(edit_mode_metadata),\n        _ => Err(anyhow!(\"Expected to be in edit mode\")),\n    }\n}\n\npub fn in_outside_workspace_mode(ctx: &Context, perm: &RepoShared) -> Result<bool> {\n    Ok(matches!(\n        operating_mode(ctx, perm)?,\n        OperatingMode::OutsideWorkspace(_)\n    ))\n}\n","sourceCodeStart":205,"sourceCodeEnd":233,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/gitbutler-operating-modes/src/lib.rs#L205-L233","documentation":"ensure_edit_mode (crates/gitbutler-operating-modes/src/lib.rs) reads the current operating mode and demands OperatingMode::Edit. The mode is derived from HEAD: edit mode means HEAD points at refs/heads/gitbutler/edit (EDIT_BRANCH_REF); the workspace ref means open-workspace mode; anything else (or detached HEAD, or unreadable edit metadata) is OutsideWorkspace. Calling an edit-mode-only API while in one of those other modes yields this error.","triggerScenarios":"Invoking edit-mode commands while HEAD is refs/heads/gitbutler/workspace (open workspace mode); HEAD on an ordinary branch or detached (outside workspace mode); edit-mode metadata unreadable, in which case operating_mode itself falls back to OutsideWorkspace; concurrent mode switches racing the call.","commonSituations":"A user (or the UI) exits edit mode while a background job still calls edit-mode APIs; automation that assumes edit mode without checking; the edit branch checked out but its metadata file damaged; race between opening a workspace and dispatching an edit command.","solutions":["Guard the call: check gitbutler_operating_modes::in_edit_mode(&ctx, &perm) first and only invoke edit-mode APIs when true","Switch into edit mode through the app's flow (checkout of refs/heads/gitbutler/edit) before calling edit-only commands","If HEAD should be the edit branch but is not, inspect `git symbolic-ref HEAD` and the edit-mode metadata under the project's GitButler dir","For UI/backend code, surface mode state and disable edit-mode actions instead of firing them blindly"],"exampleFix":"// before\nlet meta = gitbutler_operating_modes::ensure_edit_mode(&ctx, &perm)?;\n\n// after: check the predicate first and degrade gracefully\nif !gitbutler_operating_modes::in_edit_mode(&ctx, &perm)? {\n    tracing::warn!(\"skipping edit-mode action: not in edit mode (HEAD != refs/heads/gitbutler/edit)\");\n    return Ok(());\n}\nlet meta = gitbutler_operating_modes::ensure_edit_mode(&ctx, &perm)?;","handlingStrategy":"type-guard","validationCode":"// non-fatal predicate check before edit-mode-only calls\nif !gitbutler_operating_modes::in_edit_mode(&ctx, &perm)? {\n    return Ok(()); // or skip the feature in this mode\n}","typeGuard":"// in_edit_mode IS the type guard: OperatingMode -> bool narrowing\npub fn can_run_edit_mode_action(ctx: &Context, perm: &RepoShared) -> Result<bool> {\n    gitbutler_operating_modes::in_edit_mode(ctx, perm)\n}","tryCatchPattern":"match gitbutler_operating_modes::ensure_edit_mode(&ctx, &perm) {\n    Ok(meta) => run_edit_action(meta),\n    Err(err) if err.to_string().contains(\"Expected to be in edit mode\") => {\n        tracing::warn!(\"mode mismatch — HEAD is not refs/heads/gitbutler/edit\");\n        Ok(()) // degrade instead of failing the whole command\n    }\n    Err(err) => Err(err),\n}","preventionTips":["Gate every edit-mode command with in_edit_mode() at dispatch time, not after","Re-check the mode inside long-running jobs right before they touch edit state — the user may switch modes mid-flight","Treat the mode as a state machine: subscribe to mode changes and enable/disable UI actions accordingly"],"tags":["gitbutler","operating-mode","workspace","state-machine"],"backgroundTag":"operating-mode-mismatch","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}