Hmbown/CodeWhale · error · ValueError

{context}: expected 'Name <id+login@users.noreply.github.com

Error message

{context}: expected 'Name <id+login@users.noreply.github.com>'

What it means

scripts/check-coauthor-trailers.py validates identities in .github/AUTHOR_MAP and commit trailers against the strict form 'Name <id+login@users.noreply.github.com>'. This error is raised by parse_identity when the whole raw string does not match IDENTITY_RE — i.e. the '<...>' angle-bracket email part is missing or the line is not a single Name + email pair.

Source

Thrown at scripts/check-coauthor-trailers.py:133

    def is_merge_commit(self) -> bool:
        return len(self.parents.split()) > 1


def norm_key(value: str) -> str:
    return value.strip().lower()


def github_login_from_noreply(email: str) -> str | None:
    if not CANONICAL_NOREPLY_RE.match(email):
        return None
    local = email.split("@", 1)[0]
    return local.split("+", 1)[1]


def parse_identity(raw: str, context: str) -> Identity:
    match = IDENTITY_RE.match(raw)
    if not match:
        raise ValueError(f"{context}: expected 'Name <id+login@users.noreply.github.com>'")
    identity = Identity(match.group("name").strip(), match.group("email").strip())
    if not CANONICAL_NOREPLY_RE.match(identity.email):
        raise ValueError(
            f"{context}: right-hand email must be numeric GitHub noreply, got {identity.email}"
        )
    return identity


def load_author_map(path: Path) -> dict[str, Identity]:
    aliases: dict[str, Identity] = {}
    for lineno, raw_line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
        line = raw_line.split("#", 1)[0].strip()
        if not line:
            continue
        if "=" not in line:
            raise ValueError(f"{path}:{lineno}: expected 'alias = Name <email>'")
        alias, raw_identity = [part.strip() for part in line.split("=", 1)]
        identity = parse_identity(raw_identity, f"{path}:{lineno}")

View on GitHub (pinned to 8880682c63)

Solutions

  1. Fix the offending entry/trailer to exactly: Display Name <1234567+login@users.noreply.github.com>.
  2. Get the numeric id+login from the contributor's GitHub profile (the ID is the numeric account id, the login their username).
  3. Re-run scripts/check-coauthor-trailers.py locally over your commit range before pushing.
  4. If a contributor has no GitHub noreply address, coordinate with maintainers on the canonical identity to record in AUTHOR_MAP.

Example fix

# before (.github/AUTHOR_MAP)
jane = Jane Doe
# after
jane = Jane Doe <1234567+janedoe@users.noreply.github.com>
Defensive patterns

Strategy: validation

Validate before calling

import re

IDENTITY_RE = re.compile(r"^(?P<name>.+) <(?P<email>[^>]+)>$")

def identity_well_formed(raw: str) -> bool:
    return IDENTITY_RE.match(raw.strip()) is not None

Type guard

def is_canonical_identity(raw: object) -> bool:
    if not isinstance(raw, str):
        return False
    match = IDENTITY_RE.match(raw.strip())
    return bool(match) and bool(
        re.match(r"^[0-9]+\+[a-zA-Z0-9-]+@users\.noreply\.github\.com$", match.group("email"))
    )

Prevention

When it happens

Trigger: An AUTHOR_MAP entry like 'jane = Jane Doe' (no angle-bracket email) or 'jane = Jane <jane@x.com> <jane@y.com>' (two pairs); a Co-authored-by trailer whose value lacks the email portion; stray characters that break the regex.

Common situations: Editing .github/AUTHOR_MAP by hand and forgetting the noreply email; squash-merge trailers copied from patch emails; name fields containing unbalanced '<' or '>'; entries copied from a map format used by other tools (Name <email> without the numeric id+login).

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/87adfaacd75ea7ed. Report an issue: GitHub.