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
- Remove or rename the duplicated key that the message prints (JSON.stringify shows it with quotes and escapes).
- If both entries were intentional, merge their values or split them into two separate map specs.
- 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
- Keep entries alphabetically sorted so duplicates are visually obvious in review diffs.
- Derive entries from a single source object (no duplicate object keys possible) instead of hand-written tuples.
- Run the string-map generator as part of CI so bad specs fail the build, not a release.
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
- slice/str param `${ty}` is not FFI-safe; pass (ptr, len)
- ${where}: cannot parse param `${raw}`
- ${loc}: HOST_EXPORT(${e.symbol}, rust) param `${p.raw}` is a
- ${loc}: HOST_EXPORT(${e.symbol}, rust) return type `${e.ret}
- generate-string-map: ${name}: emitCaseInsensitive requires A
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/85035da8df359187.
Report an issue: GitHub.