{"record":{"id":"1b69717a97bf02b4","repo":"dotnet/runtime","slug":"expected-shortname-to-be-a-function","errorCode":null,"errorMessage":"Expected ${shortName} to be a function","messagePattern":"Expected (.+?) to be a function","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/mono/browser/runtime/exports-binding.ts","lineNumber":146,"sourceCode":"    for (const shortName in env) {\n        const stub_fn = env[shortName] as Function;\n        if (typeof stub_fn === \"function\" && stub_fn.toString().indexOf(\"runtime_idx\") !== -1) {\n            try {\n                const { runtime_idx } = stub_fn();\n                if (indexToNameMap[runtime_idx] !== undefined) throw new Error(`Duplicate runtime_idx ${runtime_idx}`);\n                indexToNameMap[runtime_idx] = shortName;\n            } catch {\n                // no-action\n            }\n        }\n    }\n\n    for (const [idx, realFn] of wasmImports.entries()) {\n        const shortName = indexToNameMap[idx];\n        // if it's not found it means the emcc linker didn't include it, which is fine\n        if (shortName !== undefined) {\n            const stubFn = env[shortName];\n            if (typeof stubFn !== \"function\") throw new Error(`Expected ${shortName} to be a function`);\n            env[shortName] = realFn;\n        }\n    }\n}\n","sourceCodeStart":128,"sourceCodeEnd":151,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/mono/browser/runtime/exports-binding.ts#L128-L151","documentation":"Thrown by replace_linker_placeholders in exports-binding.ts after it rebuilt the indexToNameMap from the emcc-generated import stubs. For each real function in wasmImports it looks up the short name in the wasm import object and asserts that env[shortName] is still a function before swapping the emcc stub for the real implementation. The assertion fires only if the stub slot was overwritten with a non-function between discovery and replacement, which indicates a corrupted or hand-modified WebAssembly import object rather than a normal usage error.","triggerScenarios":"Instantiating a custom/rebuilt dotnet wasm module whose import object was mutated externally; shipping a runtime bundle produced by a mismatched emscripten toolchain; a library initializer or third-party code overwriting Module imports before replace_linker_placeholders runs.","commonSituations":"Forking the runtime and editing the wasm imports; upgrading emscripten without rebuilding the .NET wasm runtime; an aggressive monkey-patch on the emscripten Module that replaces import stubs with non-function values.","solutions":["Rebuild the .NET wasm runtime and its JS loader with the matching emscripten version so the import stubs are generated fresh.","Remove any code that mutates the wasm imports object (env/a) before instantiation.","If you fork the runtime, ensure replace_linker_placeholders runs before any external code touches imports.env / imports.a."],"exampleFix":"// before: third-party code mutates imports\nimports.env[shortName] = null;\n// after: leave import stubs untouched until the runtime replaces them\n// (do not overwrite imports.env[shortName])","handlingStrategy":"validation","validationCode":"// before calling replace_linker_placeholders (or before instantiating the wasm)\nconst env = imports.env || imports.a;\nif (!env) throw new Error('emscripten imports.env/.a missing');\nfor (const k of Object.keys(env)) {\n  if (typeof env[k] !== 'function')\n    console.warn(`import '${k}' is not a function before linker replacement`);\n}","typeGuard":"function isFunctionImports(env: Record<string, unknown>): env is Record<string, Function> {\n  return Object.values(env).every(v => typeof v === 'function');\n}","tryCatchPattern":null,"preventionTips":["Do not mutate the emscripten Module imports object after the runtime is constructed.","Rebuild the wasm runtime and JS loader together with the same emscripten version.","Run any library initializer that patches imports before the runtime's replace_linker_placeholders step."],"tags":["wasm-imports","emscripten","linker","startup"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}