{"record":{"id":"7ffd2e2b32d3a7b1","repo":"dotnet/runtime","slug":"part-not-found-while-looking-up-functionname","errorCode":null,"errorMessage":"${part} not found while looking up ${functionName}","messagePattern":"(.+?) not found while looking up (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/invoke-js.ts","lineNumber":286,"sourceCode":"\n    let scope: any = {};\n    const parts = functionName.split(\".\");\n    if (jsModuleName) {\n        scope = importedModules.get(jsModuleName);\n        dotnetAssert.fastCheck(scope, () => `ES6 module ${jsModuleName} was not imported yet, please call JSHost.ImportAsync() first in order to invoke ${functionName}.`);\n    } else if (parts[0] === \"INTERNAL\") {\n        scope = dotnetApi.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 ${functionName}`);\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(`${functionName} 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 invokeJSFunction(functionJSHandle: JSHandle, args: JSMarshalerArguments): void {\n    assertRuntimeRunning();\n    const boundFn = getJSObjectFromJSHandle(functionJSHandle);","sourceCodeStart":268,"sourceCodeEnd":304,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/invoke-js.ts#L268-L304","documentation":"lookupJsImport walks the dotted function name (e.g. 'MyModule.Sub.Fn') through the imported JS module's scope; if any intermediate segment is undefined it throws, naming the missing part. This is the JSImport resolution path used by [JSImport] bindings after JSHost.ImportAsync has loaded the module.","triggerScenarios":"A [JSImport('A.B.C', 'mod')] whose module object lacks the expected nested path — the module wasn't imported yet, the dotted name has a typo or wrong casing, or the JS export isn't nested where the binding expects.","commonSituations":"Forgetting to await JSHost.ImportAsync('mod', url) before invoking a JSImport; renaming/moving a JS export without updating the attribute; a mismatch between the module's real export shape and the dotted name; casing differences on case-sensitive hosts.","solutions":["Call and await JSHost.ImportAsync(moduleName, url) before invoking any JSImport from that module.","Verify the dotted name in [JSImport] matches the actual nested export path — log the imported module object to inspect its shape.","Check for typos and casing in the function name and every intermediate segment."],"exampleFix":"// before\n[JSImport(\"Sub.Fn\", \"mod\")] // 'Sub' missing on module -> \"Sub not found while looking up Sub.Fn\"\n\n// after: import first, and match the export structure\nawait JSHost.ImportAsync(\"mod\", \"./mod.js\");\n// mod.js: export const Sub = { Fn: () => {} };","handlingStrategy":"validation","validationCode":"function resolvePath(module, dotted) {\n  let scope = module;\n  const parts = dotted.split(\".\");\n  for (const part of parts.slice(0, -1)) {\n    if (scope == null || !(part in scope)) return false;\n    scope = scope[part];\n  }\n  return typeof scope[parts[parts.length - 1]] === \"function\";\n}\nif (!resolvePath(importedModule, \"Sub.Fn\")) { /* wrong path / not imported */ }","typeGuard":null,"tryCatchPattern":"// C# caller: lookupJsImport errors are marshaled to .NET as JSException\ntry { await jsImport.Fn(); }\ncatch (JSException ex) when (ex.Message.Contains(\"not found while looking up\")) {\n  // module path wrong, not imported, or typo — fix the [JSImport] name / call ImportAsync\n}","preventionTips":["Always ImportAsync a module before invoking any of its JSImports.","Keep [JSImport] dotted names in sync with the JS export structure.","Add a startup smoke test that imports each module and checks the expected export path exists."],"tags":["jsimport","interop","module-resolution"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}