{"record":{"id":"21e543bc2ab4e1c9","repo":"gitbutlerapp/gitbutler","slug":"is-not-open-and-cannot-be-marked-ready","errorCode":null,"errorMessage":"{}{} is not open and cannot be marked ready","messagePattern":"(.+?)(.+?) is not open and cannot be marked ready","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/mcp/mod.rs","lineNumber":791,"sourceCode":"\n    review_view(&request.repository, &[request.review_number])\n}\n\nenum MarkReadyPreparation {\n    AlreadyReady(ReviewView),\n    Update {\n        preferred_user: Option<but_forge::ForgeUser>,\n        repository: but_forge::ForgeRepoInfo,\n        storage: but_forge_storage::Controller,\n    },\n}\n\nfn prepare_mark_review_ready(request: &MarkReviewReadyRequest) -> Result<MarkReadyPreparation> {\n    let resolved = open_repository(&request.repository)?;\n    let forge = ForgeRepository::from_context(&resolved.ctx)?;\n    let review = forge.get_review(&resolved.ctx, request.review_number)?;\n    if !review.is_open() {\n        bail!(\n            \"{}{} is not open and cannot be marked ready\",\n            review.unit_symbol,\n            review.number\n        );\n    }\n    if !review.draft {\n        return review_view_from_repository(resolved, &[request.review_number])\n            .map(MarkReadyPreparation::AlreadyReady);\n    }\n    if !forge.display.capabilities.pr_service {\n        bail!(\n            \"Marking reviews ready is not supported for {:?}\",\n            forge.display.name\n        );\n    }\n\n    let ForgeRepository {\n        preferred_user,","sourceCodeStart":773,"sourceCodeEnd":809,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but/src/command/mcp/mod.rs#L773-L809","documentation":"prepare_mark_review_ready (crates/but/src/command/mcp/mod.rs:791) loads the review from the forge and requires review.is_open(); merged or closed reviews cannot be marked ready, and the message includes the unit symbol plus number (e.g. !123 or #42). Open but non-draft reviews are fine — that path returns the view as AlreadyReady instead of erroring.","triggerScenarios":"Calling mark-review-ready on a review that is already merged or closed on the forge.","commonSituations":"Stale review numbers captured before a merge; retrying an old tool call after the PR merged; confusing issue numbers with PR numbers.","solutions":["Check the review state first with the review-view tool; only open draft reviews can be marked ready.","If the review should still be open, reopen it on the forge and retry.","If the review is already ready (not a draft), no action is needed — that case returns normally."],"exampleFix":"// before\n{ \"review_number\": 123 }  // !123 was merged yesterday\n\n// after: verify first\n{ \"review_numbers\": [123] }  // review-view shows state: open, draft\n{ \"review_number\": 123 }    // now mark ready succeeds","handlingStrategy":"validation","validationCode":"let review = forge.get_review(&resolved.ctx, request.review_number)?;\nif !review.is_open() {\n    anyhow::bail!(\"review {} is {} — only open reviews can be marked ready\", review.number, review.state);\n}","typeGuard":null,"tryCatchPattern":"match prepare_mark_review_ready(&request) {\n    Err(err) if err.to_string().contains(\"is not open\") => {\n        // re-fetch the review view and show its current state instead of retrying\n    }\n    other => other,\n}","preventionTips":["Call review-view before mark-ready to confirm the review is open and draft.","Do not retry mark-ready after a merge event; refresh state first.","Treat AlreadyReady as success — non-draft open reviews return the view without error."],"tags":["mcp","review","state","forge"],"backgroundTag":"invalid-review-state","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}