{"record":{"id":"7c4f480491cfea8a","repo":"gitbutlerapp/gitbutler","slug":"aborting-due-to-empty-pr-title","errorCode":null,"errorMessage":"Aborting due to empty PR title","messagePattern":"Aborting due to empty PR title","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/legacy/forge/review.rs","lineNumber":889,"sourceCode":"            || (!is_selected_branch && selected_branch_message.is_some()),\n        message: is_selected_branch\n            .then_some(selected_branch_message)\n            .flatten(),\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct ForgeReviewMessage {\n    pub title: String,\n    pub body: String,\n}\n\npub fn parse_review_message(content: &str) -> anyhow::Result<ForgeReviewMessage> {\n    let mut lines = content.lines();\n    let title = lines.next().unwrap_or(\"\").trim().to_string();\n\n    if title.is_empty() {\n        anyhow::bail!(\"Aborting due to empty PR title\");\n    }\n\n    // Skip any leading blank lines after the title, then collect the rest as description\n    let body = lines\n        .skip_while(|l| l.trim().is_empty())\n        .collect::<Vec<_>>()\n        .join(\"\\n\")\n        .trim()\n        .to_string();\n\n    Ok(ForgeReviewMessage { title, body })\n}\n\n#[expect(clippy::too_many_arguments)]\nasync fn publish_review_for_branch(\n    ctx: &mut Context,\n    stack_id: Option<StackId>,\n    branch_name: &str,","sourceCodeStart":871,"sourceCodeEnd":907,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but/src/command/legacy/forge/review.rs#L871-L907","documentation":"When creating/updating reviews without an explicit message, `but review` opens your editor with a template whose FIRST LINE becomes the PR title (HTML comment lines are stripped first). `parse_review_message` takes that first line, trims it, and bails when it is empty — forges require a title, so the operation aborts before anything is created.","triggerScenarios":"Saving the editor buffer with an empty or blank first line (title deleted or left empty); a misconfigured `$EDITOR`/`$GIT_EDITOR` that writes nothing or exits instantly (e.g. `true`); automation running where no real editor can open; putting the title below a leading blank line.","commonSituations":"Editor template left untouched except comments (the template itself warns 'Leaving it empty ABORTS the operation'); `EDITOR=true` in scripts/CI; editor failures in terminal multiplexers or over broken ssh sessions.","solutions":["Re-run and make the first line of the buffer a non-empty title; blank lines and comments after it are fine.","If the editor opened empty or closed instantly, fix `$EDITOR` / `$GIT_EDITOR`.","Skip the editor entirely: pass `-m/--message \"Title\"` (multi-line supported) or `-t/--default` to derive title and body from the commit message."],"exampleFix":"# before\nEDITOR=true but review create   # editor writes nothing -> Aborting due to empty PR title\n\n# after\nbut review create -m 'Add retry to sync client'\nbut review create -t              # title/body from the commit message, no editor","handlingStrategy":"validation","validationCode":"# Non-interactive: always pass the title explicitly instead of relying on an editor\nbut review create -m 'Fix pagination in sync client'\nbut review create -t   # or derive title/body from the commit message","typeGuard":"fn has_title(content: &str) -> bool {\n    content.lines().next().map(|l| !l.trim().is_empty()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Keep a non-empty first line in the review editor buffer; comment lines are stripped before parsing.","Set a real `$EDITOR`/`$GIT_EDITOR` in scripts, or pass `-m/--message` / `-t/--default`."],"tags":["cli","forge","review","editor","pr-title","gitbutler"],"backgroundTag":"empty-required-field","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-23T16:17:53.355Z"}