oven-sh/bun · error · Error

generate-string-map: duplicate key ${JSON.stringify(k)} in $

Error message

generate-string-map: duplicate key ${JSON.stringify(k)} in ${name}

What it means

generate-string-map.ts compiles a TypeScript spec (e.g. src/js_parser/defines_table.string-map.ts) into Rust match-based string lookups. Every key in the spec's `entries` array must be unique, because the generated Rust code is a match over distinct byte literals; a second occurrence would produce dead arms. The error names the offending map (`name`) and the exact duplicated key.

Source

Thrown at src/codegen/generate-string-map.ts:223

      out.push(`            let mut probe = [0u8; ${len}];`);
      out.push(`            for (d, s) in probe.iter_mut().zip(key) { *d = s.to_ascii_lowercase(); }`);
      out.push(`            ${tableName}.binary_search_by(|(k, _)| k.cmp(&probe)).ok().map(|i| ${tableName}[i].1)`);
      out.push(`        }`);
    }
  }
  out.push(`        _ => None,`);
  out.push(`    }`);
  out.push(`}`);
}

function buildOne<V>(spec: StringMapSpec<V>): string {
  const { name, valueTy, entries, emitKeys, emitIndexOf, emitCaseInsensitive, doc } = spec;
  const emitValue = spec.emitValue ?? ((v: V) => (typeof v === "string" ? JSON.stringify(v) : String(v)));

  const seen = new Set<string>();
  const seenCi = new Set<string>();
  for (const [k] of entries) {
    if (seen.has(k)) throw new Error(`generate-string-map: duplicate key ${JSON.stringify(k)} in ${name}`);
    seen.add(k);
    if (emitCaseInsensitive) {
      // eslint-disable-next-line no-control-regex
      if (!/^[\x00-\x7f]*$/.test(k)) {
        throw new Error(
          `generate-string-map: ${name}: emitCaseInsensitive requires ASCII keys; ${JSON.stringify(k)} is not`,
        );
      }
      const lk = k.toLowerCase();
      if (seenCi.has(lk)) {
        throw new Error(`generate-string-map: ${name}: keys ${JSON.stringify(k)} collide under case folding`);
      }
      seenCi.add(lk);
    }
  }

  const kvs: Array<readonly [Buffer, string]> = entries.map(([k, v]) => [Buffer.from(k, "utf8"), emitValue(v)]);
  const out: string[] = [];

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Remove or rename the duplicated key that the message prints (JSON.stringify shows it with quotes and escapes).
  2. If both entries were intentional, merge their values or split them into two separate map specs.
  3. Add a CI/lint step that dedupe-checks every *.string-map.ts before codegen runs.

Example fix

// before
export default {
  name: "DefinesTable",
  entries: [
    ["BUN_1", 1],
    ["BUN_1", 2], // duplicate key
  ],
} satisfies StringMapSpec<number>;

// after
export default {
  name: "DefinesTable",
  entries: [
    ["BUN_1", 1],
    ["BUN_2", 2],
  ],
} satisfies StringMapSpec<number>;
Defensive patterns

Strategy: validation

Validate before calling

function assertUniqueKeys(name, entries) {
  const seen = new Set();
  for (const [k] of entries) {
    if (seen.has(k)) throw new Error(`duplicate key ${JSON.stringify(k)} in ${name}`);
    seen.add(k);
  }
}
// run before: bun src/codegen/generate-string-map.ts input out.rs
assertUniqueKeys(spec.name, spec.entries);

Prevention

When it happens

Trigger: Running `bun src/codegen/generate-string-map.ts <input.string-map.ts> <out.rs>` where the input's `entries: [key, value][]` contains the same exact (case-sensitive) key string twice.

Common situations: Merging two entry lists into one map, copy-pasting an entry and changing only the value, or refactoring keys so two previously-distinct entries become identical.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/85035da8df359187. Report an issue: GitHub.