oven-sh/bun · error · Error
non-ascii character in string "${str}". this will not be a v
Error message
non-ascii character in string "${str}". this will not be a valid ASCIILiteral What it means
checkAscii (src/codegen/helpers.ts) guards strings that codegen embeds as C++ ASCIILiteral byte arrays — bundle-modules.ts checks the generated module source (line 425) and bundle-functions.ts checks each function source (line 405). A non-ASCII character would corrupt the generated literal (byte length != character length), so it throws before writing broken output.
Source
Thrown at src/codegen/helpers.ts:35
export function readdirRecursive(root: string): string[] {
const files = fs.readdirSync(root, { withFileTypes: true });
return files.flatMap(file => {
const fullPath = path.join(root, file.name);
return file.isDirectory() ? readdirRecursive(fullPath) : fullPath;
});
}
export function resolveSyncOrNull(specifier: string, from: string) {
try {
return Bun.resolveSync(specifier, from);
} catch {
return null;
}
}
export function checkAscii(str: string) {
if (!isAscii(Buffer.from(str))) {
throw new Error(`non-ascii character in string "${str}". this will not be a valid ASCIILiteral`);
}
return str;
}
export function writeIfNotChanged(file: string, contents: string) {
if (Array.isArray(contents)) contents = contents.join("");
contents = contents.replaceAll("\r\n", "\n").trim() + "\n";
try {
const oldContents = fs.readFileSync(file, "utf8");
if (oldContents === contents) {
return;
}
} catch (e) {}
try {
fs.writeFileSync(file, contents);View on GitHub (pinned to 8c5296ac45)
Solutions
- Replace the character the message prints with an ASCII equivalent or a \uXXXX escape in the JS source.
- Keep builtin module files ASCII-only (configure your editor / add an editorconfig `charset` check).
- If unicode is required at runtime, encode it as an escape sequence so the literal bytes stay ASCII.
Example fix
// before (src/js/builtins file) export const msg = "unexpected value”; // smart quote is non-ASCII // after export const msg = "unexpected value";
Defensive patterns
Strategy: validation
Validate before calling
import { isAscii } from "node:buffer";
function assertAsciiLiteral(s: string, where: string) {
if (!isAscii(Buffer.from(s))) {
const bad = [...s].find(ch => ch.charCodeAt(0) > 0x7f);
throw new Error(`${where}: non-ASCII character ${JSON.stringify(bad)} — use \\u escapes`);
}
} Type guard
const isAsciiLiteral = (s: string) => isAscii(Buffer.from(s));
Prevention
- Keep builtin module sources ASCII; express unicode via \uXXXX escapes.
- Add a lint step that rejects non-ASCII bytes in src/js/** before running codegen.
- Beware copy-paste from docs/browsers: smart quotes and dashes are the usual offenders.
When it happens
Trigger: Adding a builtin JS module or function under src/js whose source contains a non-ASCII character (unicode strings, smart quotes, non-ASCII identifiers) that ends up in the embedded literal.
Common situations: Copy-pasting code with typographic quotes or accented words into src/js builtins; pasting a unicode arrow or emoji into an error message of a builtin.
Related errors
- Builtin Bundler: do not use import.meta.require() (in ${file
- Errors in ${entrypoint}: ${errors.map(x => x[1]).join("\n")}
- Missing output for ${id}
- generate-string-map: ${name}: emitCaseInsensitive requires A
- file did not exist after write: ${outputPath}
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/ee8eb3ae6785ae5d.
Report an issue: GitHub.