Hmbown/CodeWhale · error · Error

contains duplicate checksum rows for

Error message

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

What it means

parseChecksumManifest rejects duplicate entries: if the same asset name appears twice in the manifest, the second occurrence throws this Error. Duplicate rows make the authoritative inventory ambiguous, so the parser refuses to guess which digest is correct.

Solutions

  1. Regenerate the manifest from scratch in one pass: `sha256sum * > SHA256SUMS` (overwrite, do not append).
  2. Deduplicate by filename keeping exactly one digest row per name.
  3. Fix the generator script to write with `>` instead of `>>` or to clear prior content.

Example fix

// before
cat part1.sum part1.sum > SHA256SUMS
// after
sha256sum assets/* > SHA256SUMS
Defensive patterns

Strategy: validation

Validate before calling

const names = text.split('\n').filter(Boolean).map(l => l.trim().split(/\s+/).slice(1).join(' '));
if (new Set(names).size !== names.length) throw new Error('SHA256SUMS has duplicate entries');

Try / catch

try { await checksums(manifestPath); } catch (e) { if (String(e.message).includes('duplicate checksum rows')) { console.error('Deduplicate SHA256SUMS:', e.message); process.exitCode = 1; } else throw e; }

Prevention

When it happens

Trigger: Concatenating two SHA256SUMS files that both list the same asset, or running a generator twice in append mode so a filename appears on two lines.

Common situations: CI jobs that accumulate checksum lines across runs, or manually merging checksum output from multiple build directories.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/bda040e3ce3914d8. Report an issue: GitHub.

Appendix: 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 433685b202)