Hmbown/CodeWhale · error · Error

${label} contains duplicate checksum rows for ${name}

Error message

${label} contains duplicate checksum rows for ${name}

What it means

parseChecksumManifest() found two rows for the same filename in a checksum manifest and refuses the ambiguous input. The Map-based parse keeps one digest per basename, so a duplicate row means the manifest was concatenated, double-generated, or edited and cannot attest a single hash per asset. The conflicting basename is named in the message.

Source

Thrown at scripts/release/assemble-release-assets.js:44

  const hash = crypto.createHash("sha256");
  hash.update(await fs.readFile(filePath));
  return hash.digest("hex");
}

function parseChecksumManifest(content, label) {
  const checksums = new Map();
  for (const line of content.split(/\r?\n/)) {
    const trimmed = line.trim();
    if (!trimmed) {
      continue;
    }
    const match = trimmed.match(/^([a-fA-F0-9]{64})\s+\*?(.+)$/);
    if (!match) {
      throw new Error(`${label} contains an invalid checksum row: ${trimmed}`);
    }
    const name = match[2];
    if (checksums.has(name)) {
      throw new Error(`${label} contains duplicate checksum rows for ${name}`);
    }
    checksums.set(name, match[1].toLowerCase());
  }
  return checksums;
}

function assertExactNames(actualNames, expectedNames, label) {
  const actual = new Set(actualNames);
  const expected = new Set(expectedNames);
  const missing = expectedNames.filter((name) => !actual.has(name));
  const unexpected = actualNames.filter((name) => !expected.has(name));
  if (missing.length > 0 || unexpected.length > 0 || actual.size !== actualNames.length) {
    throw new Error(
      `${label} does not match the authoritative inventory` +
        `${missing.length > 0 ? `; missing: ${missing.join(", ")}` : ""}` +
        `${unexpected.length > 0 ? `; unexpected: ${unexpected.join(", ")}` : ""}` +
        `${actual.size !== actualNames.length ? "; duplicate basenames are present" : ""}`,
    );

View on GitHub (pinned to 8880682c63)

Solutions

  1. Remove the duplicate row so each basename appears exactly once, keeping the row whose hash matches the actual file (verify with sha256sum)
  2. Prefer regenerating the manifest via the assemble script instead of editing it
  3. If two artifacts legitimately share a basename, rename one — the release inventory requires unique basenames (assertExactNames also rejects duplicates)

Example fix

# before
9d86...  codewhale-x86_64.tar.gz
4e97...  codewhale-x86_64.tar.gz   # duplicate row

# after
9d86...  codewhale-x86_64.tar.gz
Defensive patterns

Strategy: validation

Validate before calling

function findDuplicateManifestRows(content) {
  const seen = new Set();
  const duplicates = [];
  for (const line of content.split(/\r?\n/)) {
    const match = line.trim().match(/^[a-fA-F0-9]{64}\s+\*?(.+)$/);
    if (!match) continue;
    if (seen.has(match[2])) duplicates.push(match[2]);
    seen.add(match[2]);
  }
  return duplicates;
}

Prevention

When it happens

Trigger: Concatenating two manifest files covering overlapping assets; a generator appending instead of overwriting; copy-paste duplication while hand-editing; the same bundle listed under both plain and *-prefixed forms that normalize to the same name.

Common situations: Merging manifests from parallel CI jobs without dedupe; a buggy custom packaging script appending rows on retry; manual re-addition of a 'missing' row that was actually present.

Related errors


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