oven-sh/bun · error · Error

Expected filename for $${call_type} to have ${ext} extension

Error message

Expected filename for $${call_type} to have ${ext} extension, got ${JSON.stringify(filename)}

What it means

generate-js2native.ts maps each native-call intrinsic ($bind/$bindgenFn, $rust, $cpp, $zz, ...) to a source file, and first validates the filename's extension matches the call type: .bind.ts for bind, .rs for rust, .<call_type> otherwise. This error fires at registration time when, for example, $rust() is given a .ts path or a $cpp() call points at a .bind.ts file. The message shows both the expected extension and the exact offending filename.

Source

Thrown at src/codegen/generate-js2native.ts:111

  "shell.rs": "runtime/shell/shell.rs",
  "sourcemap/InternalSourceMap.rs": "sourcemap/InternalSourceMap.rs",
  "string/immutable/unicode.rs": "bun_core/string/immutable/unicode.rs",
  "subprocess.rs": "runtime/api/bun/subprocess.rs",
  "sys.rs": "sys/sys.rs",
  "sys/Error.rs": "sys/Error.rs",
  "udp_socket.rs": "runtime/socket/udp_socket.rs",
  "upgrade_command.rs": "runtime/cli/upgrade_command.rs",
  "virtual_machine_exports.rs": "jsc/virtual_machine_exports.rs",
};

function callBaseName(x: string) {
  return x.split(/[^A-Za-z0-9]/g).pop()!;
}

function resolveNativeFileId(call_type: NativeCallType, filename: string) {
  const ext = call_type === "bind" ? ".bind.ts" : call_type === "rust" ? ".rs" : `.${call_type}`;
  if (!filename.endsWith(ext)) {
    throw new Error(`Expected filename for $${call_type} to have ${ext} extension, got ${JSON.stringify(filename)}`);
  }

  if (call_type === "rust") {
    const relative = rustIdentifierPaths[filename];
    if (!relative) {
      throw new Error(
        `Unknown $rust() file identifier ${JSON.stringify(filename)}. Add it to rustIdentifierPaths in src/codegen/generate-js2native.ts.`,
      );
    }
    return path.join(srcDir, relative.replaceAll("/", sep));
  }

  filename = filename.replaceAll("/", sep);

  const resolved = sourceFiles.find(file => file.endsWith(sep + filename));
  if (!resolved) {
    const fnName = call_type === "bind" ? "bindgenFn" : call_type;
    throw new Error(`Could not find file ${filename} in $${fnName} call`);

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Read the message: it names the expected extension for that specific call type and the filename you passed
  2. Fix the argument to a real file with the right extension, e.g. $rust("udp_socket.rs", "BunUDPListen")
  3. If the file genuinely has a different extension, use the matching intrinsic (or rename the file) rather than fighting the check

Example fix

// before
const listen = $rust("udp_socket", "BunUDPListen");

// after
const listen = $rust("udp_socket.rs", "BunUDPListen");
Defensive patterns

Strategy: validation

Validate before calling

// check every native-call filename against its expected extension
const expectedExt = { bind: ".bind.ts", rust: ".rs" } as Record<string, string>;
function validNativeCall(callType: string, filename: string): boolean {
  const ext = expectedExt[callType] ?? `.${callType}`;
  return filename.endsWith(ext);
}

Prevention

When it happens

Trigger: Calling $rust("my_api") or $rust("my_api.ts") instead of $rust("my_api.rs"); passing a path with the wrong suffix to any $<call_type>(filename, symbol) intrinsic in a .bind.ts file or generated-classes input; typos like `.bind.tsx`.

Common situations: Adding new Rust-implemented bindings by copying a $bindgenFn(...) line and switching only the symbol; file renames (.cpp → .cc) that break the extension contract; autocomplete inserting the wrong sibling file.

Related errors


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