GitoxideLabs/gitoxide · error · anyhow::Error

could not parse date

Error message

could not parse {field} date

What it means

Raised while parsing a reword/commit edit: the `author` or `committer` date string extracted from an instruction line could not be parsed by `gix::date::parse`. The date text must be UTF-8 and match a date format gitoxide understands.

Solutions

  1. Use a canonical date format such as ISO 8601 (`2024-01-15T10:30:00+00:00`) or a raw unix epoch timestamp with offset (`@1705314600 +0000`)
  2. Validate the date string with `gix::date::parse` before writing it into the edit/instruction
  3. Fix encoding issues so the field is valid UTF-8

Example fix

// before
committer Foo <f@x> Not A Date
// after
committer Foo <f@x> 2024-01-15T10:30:00+00:00
Defensive patterns

Strategy: validation

Validate before calling

fn valid_date(s: &str) -> bool {
    gix::date::parse(s, None).is_ok()
}
// call before building the edit instruction

Try / catch

match gix::date::parse(value, None) {
    Ok(time) => /* use time */,
    Err(e) => eprintln!("invalid {field} date {:?}: {}", value, e),
}

Prevention

When it happens

Trigger: `gix::date::parse()` fails on the value of an author/committer field when parsing a reword instruction (e.g. in interactive-rebase todo-style edits).

Common situations: Hand-edited rebase todo files with malformed or nonstandard date strings; dates in formats unsupported by gix (e.g. unusual RFC forms or locale formats); non-UTF-8 bytes in the date field (that raises a distinct 'not UTF-8' context first).

Related errors


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

Appendix: source

Thrown at gix-tix/src/edit/reword.rs:449

    }
    out.into()
}

fn header<'a>(line: Option<&'a [u8]>, prefix: &[u8]) -> Result<&'a [u8]> {
    trim_cr(line.context("a commit header is missing")?)
        .strip_prefix(prefix)
        .filter(|value| !value.is_empty())
        .with_context(|| format!("expected a non-empty {} header", prefix[..prefix.len() - 2].as_bstr()))
}

fn trim_cr(line: &[u8]) -> &[u8] {
    line.strip_suffix(b"\r").unwrap_or(line)
}

fn date(value: &[u8], field: &str) -> Result<gix::date::Time> {
    let value = std::str::from_utf8(value).with_context(|| format!("{field} date is not UTF-8"))?;
    gix::date::parse(value, None)
        .map_err(|err| anyhow::Error::new(err.into_error()))
        .with_context(|| format!("could not parse {field} date"))
}

pub(super) fn actor(value: &[u8], time: gix::date::Time, field: &str) -> Result<gix::actor::Signature> {
    let parsed = gix::actor::SignatureRef::from_bytes(value)
        .with_context(|| format!("could not parse {field} identity"))?
        .trim();
    if parsed.name.is_empty() || parsed.email.is_empty() || !parsed.time.is_empty() {
        anyhow::bail!("{field} must be written as Name <email>");
    }
    Ok(gix::actor::Signature {
        name: parsed.name.into(),
        email: parsed.email.into(),
        time,
    })
}

#[cfg(test)]

View on GitHub (pinned to e73179060b)