{"record":{"id":"242dcf8974707480","repo":"oven-sh/bun","slug":"expected-filename-for-call-type-to-have-ext","errorCode":null,"errorMessage":"Expected filename for $${call_type} to have ${ext} extension, got ${JSON.stringify(filename)}","messagePattern":"Expected filename for \\$(.+?) to have (.+?) extension, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/codegen/generate-js2native.ts","lineNumber":111,"sourceCode":"  \"shell.rs\": \"runtime/shell/shell.rs\",\n  \"sourcemap/InternalSourceMap.rs\": \"sourcemap/InternalSourceMap.rs\",\n  \"string/immutable/unicode.rs\": \"bun_core/string/immutable/unicode.rs\",\n  \"subprocess.rs\": \"runtime/api/bun/subprocess.rs\",\n  \"sys.rs\": \"sys/sys.rs\",\n  \"sys/Error.rs\": \"sys/Error.rs\",\n  \"udp_socket.rs\": \"runtime/socket/udp_socket.rs\",\n  \"upgrade_command.rs\": \"runtime/cli/upgrade_command.rs\",\n  \"virtual_machine_exports.rs\": \"jsc/virtual_machine_exports.rs\",\n};\n\nfunction callBaseName(x: string) {\n  return x.split(/[^A-Za-z0-9]/g).pop()!;\n}\n\nfunction resolveNativeFileId(call_type: NativeCallType, filename: string) {\n  const ext = call_type === \"bind\" ? \".bind.ts\" : call_type === \"rust\" ? \".rs\" : `.${call_type}`;\n  if (!filename.endsWith(ext)) {\n    throw new Error(`Expected filename for $${call_type} to have ${ext} extension, got ${JSON.stringify(filename)}`);\n  }\n\n  if (call_type === \"rust\") {\n    const relative = rustIdentifierPaths[filename];\n    if (!relative) {\n      throw new Error(\n        `Unknown $rust() file identifier ${JSON.stringify(filename)}. Add it to rustIdentifierPaths in src/codegen/generate-js2native.ts.`,\n      );\n    }\n    return path.join(srcDir, relative.replaceAll(\"/\", sep));\n  }\n\n  filename = filename.replaceAll(\"/\", sep);\n\n  const resolved = sourceFiles.find(file => file.endsWith(sep + filename));\n  if (!resolved) {\n    const fnName = call_type === \"bind\" ? \"bindgenFn\" : call_type;\n    throw new Error(`Could not find file ${filename} in $${fnName} call`);","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/src/codegen/generate-js2native.ts#L93-L129","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Read the message: it names the expected extension for that specific call type and the filename you passed","Fix the argument to a real file with the right extension, e.g. $rust(\"udp_socket.rs\", \"BunUDPListen\")","If the file genuinely has a different extension, use the matching intrinsic (or rename the file) rather than fighting the check"],"exampleFix":"// before\nconst listen = $rust(\"udp_socket\", \"BunUDPListen\");\n\n// after\nconst listen = $rust(\"udp_socket.rs\", \"BunUDPListen\");","handlingStrategy":"validation","validationCode":"// check every native-call filename against its expected extension\nconst expectedExt = { bind: \".bind.ts\", rust: \".rs\" } as Record<string, string>;\nfunction validNativeCall(callType: string, filename: string): boolean {\n  const ext = expectedExt[callType] ?? `.${callType}`;\n  return filename.endsWith(ext);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Memorize the pairing: $bind → *.bind.ts, $rust → *.rs, $cpp → *.cpp — the intrinsic name mirrors the extension","Let your editor's path autocomplete pick the real file instead of typing extensions by hand"],"tags":["codegen","bindings","js2native","configuration"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}