dotnet/runtime · error · Error

not found while looking up

Error message

${part} not found while looking up ${functionName}

What it means

lookupJsImport() resolves a dotted JSImport function name (e.g. 'MyModule.subNamespace.helper') against an imported ES module, dotnetApi.INTERNAL, or globalThis. It walks intermediate parts; if any intermediate property is missing (newscope is falsy) it throws naming the missing part and the full function name being looked up.

Solutions

  1. Verify the exact dotted path in the [JSImport(...)] attribute matches the shape of the object exported by the JS module registered via JSHost.ImportAsync.
  2. Log/inspect the imported module object right after JSHost.ImportAsync to confirm each intermediate segment exists.
  3. Correct typos in intermediate namespace segments or update the JS module to export the expected nested structure.
  4. If using globalThis/INTERNAL prefixes, confirm the prefix is spelled exactly ('globalThis.', 'INTERNAL.').

Example fix

// before - C#
[JSImport("globals.math.add", "m")]
// m.js exports: export const math = { add: ... } but 'globals' does not exist

// after
[JSImport("math.add", "m")]
// or fix the module so the dotted path resolves
Defensive patterns

Strategy: type-guard

Validate before calling

// Before binding, confirm every intermediate segment of the dotted path exists.
function resolveDottedPath(scope: any, dotted: string): any | undefined {
  let s = scope;
  for (const part of dotted.split(".").slice(0, -1)) {
    if (s == null || !(part in s)) return undefined;
    s = s[part];
  }
  return s;
}

const mod = await JSHost.ImportAsync("m", "./m.js");
const inter = resolveDottedPath(mod, "a.b.fn");
if (inter === undefined) console.error("intermediate missing for a.b.fn");

Type guard

function hasNestedProperty(obj: any, path: string): boolean {
  let s = obj;
  for (const p of path.split(".")) {
    if (s == null || typeof s !== "object" || !(p in s)) return false;
    s = s[p];
  }
  return true;
}

Try / catch

null

Prevention

When it happens

Trigger: A [JSImport] attribute names a function path where an intermediate segment is absent on the imported module object. E.g. JSHost.ImportAsync('m','./m.js') registered a module whose export is { fn: ... } but the [DllImport] uses 'm.utils.fn' where 'utils' does not exist.

Common situations: Typo in the [JSImport] function name or module name; the JS module was refactored/renamed and an intermediate namespace was removed; the module export shape changed (named export moved); looking up a property on a function-valued export instead of an object.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/7ffd2e2b32d3a7b1. Report an issue: GitHub.

Appendix: source

Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/invoke-js.ts:286

    let scope: any = {};
    const parts = functionName.split(".");
    if (jsModuleName) {
        scope = importedModules.get(jsModuleName);
        dotnetAssert.fastCheck(scope, () => `ES6 module ${jsModuleName} was not imported yet, please call JSHost.ImportAsync() first in order to invoke ${functionName}.`);
    } else if (parts[0] === "INTERNAL") {
        scope = dotnetApi.INTERNAL;
        parts.shift();
    } else if (parts[0] === "globalThis") {
        scope = globalThis;
        parts.shift();
    }

    for (let i = 0; i < parts.length - 1; i++) {
        const part = parts[i];
        const newscope = scope[part];
        if (!newscope) {
            throw new Error(`${part} not found while looking up ${functionName}`);
        }
        scope = newscope;
    }

    const fname = parts[parts.length - 1];
    const fn = scope[fname];

    if (typeof (fn) !== "function") {
        throw new Error(`${functionName} must be a Function but was ${typeof fn}`);
    }

    // if the function was already bound to some object it would stay bound to original object. That's good.
    return fn.bind(scope);
}

export function invokeJSFunction(functionJSHandle: JSHandle, args: JSMarshalerArguments): void {
    assertRuntimeRunning();
    const boundFn = getJSObjectFromJSHandle(functionJSHandle);

View on GitHub (pinned to 60108ba66e)