dotnet/aspnetcore · error · Error

Method not found

Error message

Method not found: ${method}

What it means

Thrown when the dotnet-worker exports object has been initialized (workerExports is non-empty) but the requested dotted method path (e.g. 'MyLib.Foo.Bar') does not resolve to a function. The path is split on '.' and walked with reduce; any missing segment, or a non-function leaf, triggers this.

Solutions

  1. Log Object.keys(workerExports) and inspect the actual exported surface to confirm the path.
  2. Match the method string exactly to the [JSExport] namespace.type.method, case-sensitive.
  3. Ensure the assemblyName passed to init matches the assembly containing the export.
  4. If the export was renamed, update the JS caller; do not rely on duck-typing across versions.

Example fix

// before
worker.postMessage({ method: 'MyLib.Calc.Add', args: [1,2], requestId });
// JSExport is on MyLib.Calculator.Add → 'Calc.Add is not a function'

// after — match the exported type name exactly
worker.postMessage({ method: 'MyLib.Calculator.Add', args: [1,2], requestId });
Defensive patterns

Strategy: validation

Validate before calling

// Validate the method path resolves before posting
function methodExists(exports: any, dotted: string): boolean {
  const fn = dotted.split('.').reduce((o, k) => o?.[k], exports);
  return typeof fn === 'function';
}
if (!methodExists(workerExports, method)) {
  console.error(`Available exports:`, Object.keys(workerExports));
  throw new Error(`Method not found: ${method}`);
}

Type guard

function isExportedFunction(exports: any, path: string): exports is Record<string, Function> {
  const fn = path.split('.').reduce((o, k) => o?.[k], exports);
  return typeof fn === 'function';
}

Try / catch

try {
  const result = await fn(...args);
  self.postMessage({ type: 'result', requestId, result });
} catch (e) {
  if (/Method not found/.test((e as Error).message)) {
    self.postMessage({ type: 'result', requestId, error: `${e.message}. Available: ${Object.keys(workerExports).join(', ')}` });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling worker.postMessage with a method string whose namespace/type/method does not match the [JSExport] surface of the loaded assembly; method name typo; the export is on a different type than expected; the export exists but is a property/constant, not a function.

Common situations: Renaming an exported method in C# without updating the JS caller; using the wrong assemblyName so a different (or older) export surface is loaded; casing mismatch (C# is case-sensitive); calling a static field rather than a static method.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/fffba7245f606562. Report an issue: GitHub.

Appendix: source

Thrown at src/ProjectTemplates/Web.ProjectTemplates/content/BlazorWebWorker-CSharp/wwwroot/dotnet-web-worker.js:40

    }
}

self.addEventListener('message', async (e) => {
    if (e.data.type === 'init') {
        await initialize(e.data.dotnetJsUrl, e.data.assemblyName);
        return;
    }

    const { method, args, requestId } = e.data;

    try {
        if (Object.keys(workerExports).length === 0) {
            throw new Error(startupError || "Worker .NET runtime not loaded");
        }

        const fn = method.split('.').reduce((obj, part) => obj?.[part], workerExports);
        if (typeof fn !== 'function') {
            throw new Error(`Method not found: ${method}`);
        }

        const result = await fn(...args);
        self.postMessage({ type: "result", requestId, result }, collectTransferables(result));
    } catch (err) {
        self.postMessage({ type: "result", requestId, error: err?.message ?? String(err) });
    }
});

function collectTransferables(value) {
    if (ArrayBuffer.isView(value)) return [value.buffer];
    if (value instanceof ArrayBuffer) return [value];
    return [];
}

View on GitHub (pinned to 3600ca084e)