dotnet/runtime · error · Error

method instrumentation is not enabled, please enable it…

Error message

method instrumentation is not enabled, please enable it with WasmPerformanceInstrumentation MSBuild property

What it means

collectCpuSamples() checks loaderConfig.environmentVariables['DOTNET_WasmPerformanceInstrumentation'] and throws if unset. Method instrumentation must be baked in at build time via the WasmPerformanceInstrumentation MSBuild property because the runtime needs to JIT-instrument method entry/exit probes. The env var is the runtime-side signal that the build produced an instrumented image.

Solutions

  1. Add <WasmPerformanceInstrumentation>true</WasmPerformanceInstrumentation> to the .csproj and republish.
  2. Confirm both: the MSBuild property at build AND loaderConfig.environmentVariables.DOTNET_WasmPerformanceInstrumentation at runtime (the loader auto-sets it when the property is true).
  3. If you cannot rebuild, use collectMetrics (counters) instead — they do not need instrumentation.
  4. Verify the boot JSON contains the env var after publish.

Example fix

// before: published normally
collectCpuSamples(); // throws

// after: csproj
<PropertyGroup>
  <WasmPerformanceInstrumentation>true</WasmPerformanceInstrumentation>
</PropertyGroup>
// then dotnet publish, then collectCpuSamples works
Defensive patterns

Strategy: validation

Validate before calling

function isInstrumentationEnabled(): boolean {
  return !!dotnetApi.getConfig().environmentVariables?.['DOTNET_WasmPerformanceInstrumentation'];
}
if (!isInstrumentationEnabled()) {
  console.error('Rebuild with <WasmPerformanceInstrumentation>true</WasmPerformanceInstrumentation>');
}

Type guard

function isInstrumentedBuild(): boolean {
  return !!dotnetApi.getConfig().environmentVariables?.['DOTNET_WasmPerformanceInstrumentation'];
}

Try / catch

try { await collectCpuSamples(); } catch (e) {
  if (/WasmPerformanceInstrumentation/.test((e as Error).message)) {
    // tell user to rebuild with instrumentation, or fall back to counters
    await collectMetrics();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling collectCpuSamples() on a build published without <WasmPerformanceInstrumentation>true</WasmPerformanceInstrumentation>. Setting the env var manually without rebuilding (runtime checks both build and env). Publishing Release without the property.

Common situations: Trying to profile a production build that was published for size. Enabling DOTNET_WasmPerformanceInstrumentation in config but forgetting the MSBuild property. SDK upgrade resetting the property.

Related errors


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

Appendix: source

Thrown at src/native/libs/System.Native.Browser/diagnostics/dotnet-cpu-profiler.ts:17

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { DiagnosticCommandOptions } from "../types";

import { commandResumeRuntime, commandStopTracing, commandSampleProfiler } from "./client-commands";
import { dotnetApi, dotnetLoaderExports, Module } from "./cross-module";
import { serverSession, setupJsClient } from "./diagnostic-server-js";
import { IDiagnosticSession } from "./types";

export function collectCpuSamples(options?: DiagnosticCommandOptions, startup?: boolean): Promise<Uint8Array[]> {
    if (!options) options = {};
    if (!startup && !serverSession) {
        throw new Error("No active JS diagnostic session");
    }
    if (!dotnetApi.getConfig().environmentVariables!["DOTNET_WasmPerformanceInstrumentation"]) {
        throw new Error("method instrumentation is not enabled, please enable it with WasmPerformanceInstrumentation MSBuild property");
    }

    const onClosePromise = dotnetLoaderExports.createPromiseCompletionSource<Uint8Array[]>();
    function onSessionStart(session: IDiagnosticSession): void {
        session.sendCommand(commandResumeRuntime());
        // stop tracing after period of monitoring
        Module.safeSetTimeout(() => {
            session.sendCommand(commandStopTracing(session.sessionId));
        }, 1000 * (options?.durationSeconds ?? 60));
    }

    setupJsClient({
        onClosePromise: onClosePromise,
        skipDownload: options.skipDownload,
        commandOnAdvertise: () => commandSampleProfiler(options),
        onSessionStart,
    }, startup);
    return onClosePromise.promise;

View on GitHub (pinned to 60108ba66e)