nikivdev/code · error

missing PR title (expected a non-empty line under `# Title`)

Error message

missing PR title (expected a non-empty line under `# Title`)

What it means

parse_title_body parses a PR description file that must contain a `# Title` heading followed by a non-empty title line, plus a body. It throws this error when the title section is absent or contains only whitespace, because a PR cannot be created or edited without a title.

Source

Thrown at src/pr_edit.rs:615

        }
        if l.trim() == "# Description" {
            while let Some(nl) = lines.peek() {
                if nl.trim().is_empty() {
                    lines.next();
                } else {
                    break;
                }
            }
            for rest in lines {
                body_lines.push(rest.to_string());
            }
            break;
        }
    }

    let title = title.unwrap_or_default().trim().to_string();
    if title.is_empty() {
        bail!("missing PR title (expected a non-empty line under `# Title`)");
    }
    let body = body_lines.join("\n").trim_end().to_string();
    Ok((title, body))
}

fn write_index(dir: &Path, idx: &IndexFile) -> Result<()> {
    let path = dir.join(INDEX_FILENAME);
    let json = serde_json::to_string_pretty(idx)?;
    std::fs::write(path, json)?;
    Ok(())
}

/// Best-effort helper for other codepaths (e.g. `f pr open edit`) to register mappings for files
/// that don't (yet) have frontmatter.
pub fn index_upsert_file(path: &Path, repo: &str, pr: u64) -> Result<()> {
    let dir = pr_edit_dir()?;
    std::fs::create_dir_all(&dir)?;
    let mut idx = load_index(&dir).unwrap_or_default();

View on GitHub (pinned to a747e741ae)

Solutions

  1. Add a non-empty title line directly under the `# Title` heading in the PR file
  2. Verify the heading is exactly `# Title` so the parser recognizes the section
  3. Re-sync or restore the file from the template if the title section was accidentally deleted
  4. Trim stray whitespace-only lines under the heading

Example fix

// before
# Title

Some body text...
// after
# Title
Add support for retrying failed uploads

Some body text...
Defensive patterns

Strategy: validation

Validate before calling

let content = std::fs::read_to_string("PR.md")?;
let has_title = content.lines()
    .collect::<Vec<_>>()
    .windows(2)
    .any(|w| w[0].trim() == "# Title" && !w[1].trim().is_empty());
if !has_title { anyhow::bail!("PR file lacks a title under `# Title`"); }

Type guard

fn has_title_section(content: &str) -> bool {
    let mut lines = content.lines().map(str::trim);
    while let Some(line) = lines.next() {
        if line == "# Title" {
            return lines.next().map_or(false, |t| !t.is_empty());
        }
    }
    false
}

Try / catch

match parse_title_body(&content) {
    Ok((title, body)) if !title.is_empty() => sync_file(title, body)?,
    Err(e) => eprintln!("Fix PR file first: {e}"),
}

Prevention

When it happens

Trigger: Running sync_file on a PR markdown file where the `# Title` heading is missing, or the line(s) under it are empty/whitespace only.

Common situations: Hand-edited PR description files where the user deleted the title; templates with a placeholder like `# Title` and nothing beneath it; automated tools that regenerated the file without the title; trailing whitespace that looks like content.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/c2a1463c6d6b1837. Report an issue: GitHub.