{"record":{"id":"9b7dcebd9d58a96f","repo":"dotnet/runtime","slug":"part-not-found-while-looking-up-function-name","errorCode":null,"errorMessage":"${part} not found while looking up ${function_name}","messagePattern":"(.+?) not found while looking up (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/mono/browser/runtime/invoke-js.ts","lineNumber":404,"sourceCode":"        scope = importedModules.get(js_module_name);\n        if (WasmEnableThreads) {\n            mono_assert(scope, () => `ES6 module ${js_module_name} was not imported yet, please call JSHost.ImportAsync() on the UI or JSWebWorker thread first in order to invoke ${function_name}.`);\n        } else {\n            mono_assert(scope, () => `ES6 module ${js_module_name} was not imported yet, please call JSHost.ImportAsync() first in order to invoke ${function_name}.`);\n        }\n    } else if (parts[0] === \"INTERNAL\") {\n        scope = INTERNAL;\n        parts.shift();\n    } else if (parts[0] === \"globalThis\") {\n        scope = globalThis;\n        parts.shift();\n    }\n\n    for (let i = 0; i < parts.length - 1; i++) {\n        const part = parts[i];\n        const newscope = scope[part];\n        if (!newscope) {\n            throw new Error(`${part} not found while looking up ${function_name}`);\n        }\n        scope = newscope;\n    }\n\n    const fname = parts[parts.length - 1];\n    const fn = scope[fname];\n\n    if (typeof (fn) !== \"function\") {\n        throw new Error(`${function_name} must be a Function but was ${typeof fn}`);\n    }\n\n    // if the function was already bound to some object it would stay bound to original object. That's good.\n    return fn.bind(scope);\n}\n\nexport function set_property (self: any, name: string, value: any): void {\n    mono_check(self, \"Null reference\");\n    self[name] = value;","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/mono/browser/runtime/invoke-js.ts#L386-L422","documentation":"Thrown by mono_wasm_lookup_js_import when walking the dotted segments of a [JSImport]-annotated function name and an intermediate property is not present on the scope object. The runtime splits the function name on '.' and traverses each intermediate part; if any non-final segment is undefined, it throws before even checking whether the final name is callable.","triggerScenarios":"Produced when binding a [JSImport] whose name contains intermediate path segments that do not exist on the resolved scope. E.g. [JSImport(\"Foo.Bar.Baz\")] when the imported module/scope has Foo but no Foo.Bar property.","commonSituations":"Typo in the JSImport string; renamed/moved a JS export but did not update the attribute; the JS module was not imported via JSHost.ImportAsync before the [JSImport] binding ran; mismatch between the dotted path and the actual export shape (e.g. flat export referenced via nested path).","solutions":["Verify the JSImport attribute string exactly matches the export path in your JS module (check spelling and segment order).","Ensure you awaited JSHost.ImportAsync(moduleName, url) for the module before invoking the import.","Check the actual shape of the imported module (console.log the module object) to confirm the intermediate properties exist.","Flatten the export or fix the attribute to match the real structure."],"exampleFix":"// before: JS exports a flat function but JSImport uses a nested path\n// JS:  export function doThing() {}\n// C#: [JSImport(\"myMod.Sub.doThing\")] static partial void DoThing();\n\n// after: match the real export shape\n// C#: [JSImport(\"myMod.doThing\")] static partial void DoThing();\n// and import first: await JSHost.ImportAsync(\"myMod\", \"./myMod.js\");","handlingStrategy":"validation","validationCode":"// Verify each intermediate segment exists before binding [JSImport]\nfunction pathResolvesToScope(scope, dotted) {\n  let s = scope;\n  for (const part of dotted.split('.').slice(0, -1)) {\n    if (s == null || !(part in s)) return false;\n    s = s[part];\n  }\n  return s != null;\n}\nif (!pathResolvesToScope(myModule, jsImportName)) { /* fix the path or import the module */ }","typeGuard":"function isImportPathValid(scope: any, dotted: string): boolean {\n  let s = scope;\n  for (const part of dotted.split('.').slice(0, -1)) {\n    if (s == null || typeof s !== 'object' || !(part in s)) return false;\n    s = s[part];\n  }\n  return true;\n}","tryCatchPattern":null,"preventionTips":["Always await JSHost.ImportAsync(moduleName, url) before invoking [JSImport]s in that module.","Keep the JSImport attribute string in sync with the actual export path (use source-gen or tests).","Write a smoke test that resolves all JSImport paths at startup."],"tags":["jsimport","interop","module-resolution"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}