GitoxideLabs/gitoxide · error

a quoted reference name is not closed

Error message

a quoted reference name is not closed

What it means

`parse_ref_line` parses a `(name1, name2, …)` reference line with C-style quoting and backslash escapes. If, after scanning the whole body, the parser is still inside a quoted section or a pending escape (an odd number of `"` or a trailing `\`), it throws this error because the token stream is unterminated and names cannot be split reliably.

Solutions

  1. Add the missing closing `"` around the quoted reference name.
  2. Remove the dangling trailing `\` or double it (`\\`) if a literal backslash is intended.
  3. Avoid quoting altogether — plain, comma-separated reference names need no quotes.

Example fix

// before
("refs/heads/main, refs/tags/v1)

// after
("refs/heads/main", "refs/tags/v1")
Defensive patterns

Strategy: validation

Validate before calling

// Rust: quick balance check for quotes/backslashes in a reference-line body
fn quotes_balanced(body: &str) -> bool {
    let mut quoted = false;
    let mut escaped = false;
    for b in body.bytes() {
        if escaped { escaped = false; continue; }
        match b {
            b'\\' if quoted => escaped = true,
            b'"' => quoted = !quoted,
            _ => {}
        }
    }
    !quoted && !escaped
}

Try / catch

match parse_plan(&repo, text) {
    Ok(plan) => apply(plan),
    Err(e) if e.to_string().contains("quoted reference name is not closed") => {
        eprintln!("Fix unbalanced quotes/backslash in the (…) reference line.");
        Err(e)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `parse` with a reference line like `("refs/heads/main)` or `("branch ")` with a missing closing quote, or a name ending in a lone backslash `(refs/heads/main\)`.`

Common situations: Manual editing of the reference line drops a closing quote; a shell/editor eats a trailing backslash; quoting rules from other tools are copied in (e.g. single quotes, which this parser does not treat as quotes).

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/a64436ee5a9862be. Report an issue: GitHub.

Appendix: source

Thrown at gix-tix/src/edit/todo.rs:1100

    let mut quoted = false;
    let mut escaped = false;
    for (index, byte) in body.bytes().enumerate() {
        if escaped {
            escaped = false;
            continue;
        }
        match byte {
            b'\\' if quoted => escaped = true,
            b'"' => quoted = !quoted,
            b',' if !quoted => {
                ranges.push(&body[start..index]);
                start = index + 1;
            }
            _ => {}
        }
    }
    if quoted || escaped {
        anyhow::bail!("a quoted reference name is not closed");
    }
    ranges.push(&body[start..]);
    let mut out = Vec::with_capacity(ranges.len());
    for item in ranges {
        let item = item.trim();
        if item.is_empty() {
            anyhow::bail!("a reference line contains an empty name");
        }
        let (marked, item) = item.strip_prefix('@').map_or((false, item), |item| (true, item));
        let encoded = item.as_bytes().as_bstr();
        let (name, consumed) = gix::quote::ansi_c::undo(encoded)
            .map_err(gix::Exn::into_error)
            .context("could not unquote a reference name")?;
        if !encoded[consumed..].trim().is_empty() {
            anyhow::bail!("a reference name has trailing data");
        }
        if name.is_empty() {
            anyhow::bail!("a reference name is empty");

View on GitHub (pinned to e73179060b)