dotnet/runtime · error · Error
Unrecognized asset behavior
Error message
Unrecognized asset behavior:${asset.behavior}, for asset ${asset.name} What it means
Thrown by `instantiate_asset` in the .NET WebAssembly asset loader when an asset's `behavior` field does not match any case of the dispatch switch (dotnetwasm, js-module-diagnostics, symbols, resource, assembly, pdb, heap, icu, vfs). The runtime cannot decide how to load the asset, so it errors rather than silently skipping it. This is a configuration/contract error in the asset manifest produced by the .NET WASI/browser build.
Solutions
- Inspect `config.assets` at runtime (log `runtimeHelpers.config.assets`) and find the entry whose `behavior` is not in {dotnetwasm, js-module-diagnostics, symbols, resource, assembly, pdb, heap, icu, vfs}.
- Re-generate the assets config by re-running the .NET wasm publish step with the runtime that is actually loaded.
- Remove or correct any hand-added asset entries with an unsupported behavior.
- If a genuinely new behavior is required, extend the switch in assets.ts:25 to handle it.
Example fix
// before: typo'd behavior in the config
config.assets = [{ name: 'MyLib.dll', behavior: 'asembly' }]; // throws
// after: use a supported behavior literal
config.assets = [{ name: 'MyLib.dll', behavior: 'assembly' }]; Defensive patterns
Strategy: validation
Validate before calling
const KNOWN_BEHAVIORS = new Set(['dotnetwasm','js-module-diagnostics','symbols','resource','assembly','pdb','heap','icu','vfs']);
function validateAssets (assets) {
return assets.filter(a => !KNOWN_BEHAVIORS.has(a.behavior));
}
const bad = validateAssets(runtimeHelpers.config.assets || []); if (bad.length) console.error('bad assets', bad); Type guard
type AssetBehavior = 'dotnetwasm'|'js-module-diagnostics'|'symbols'|'resource'|'assembly'|'pdb'|'heap'|'icu'|'vfs';
function isAssetBehavior (v: unknown): v is AssetBehavior {
return typeof v === 'string' && ['dotnetwasm','js-module-diagnostics','symbols','resource','assembly','pdb','heap','icu','vfs'].includes(v);
} Prevention
- Never hand-edit the generated assets config; regenerate it via `dotnet publish`.
- If you must inject custom assets, restrict to the known behaviors and validate before passing to the runtime.
- Log `runtimeHelpers.config.assets` at startup in dev builds to catch typos early.
When it happens
Trigger: The runtime iterates `runtimeHelpers.config.assets` and calls `instantiate_asset(asset, url, bytes)`. If `asset.behavior` is undefined, null, a typo, or a value produced by a newer SDK that this runtime build does not understand, execution falls to the `default:` branch at src/mono/browser/runtime/assets.ts:60-61. Custom asset entries injected through `assets` config that don't use one of the enumerated behaviors also trip it.
Common situations: Hand-editing the `assets` JSON in the runtime config and misspelling a behavior; mixing a runtime bundle with a `dotnet.runtime.js` from a different SDK that emits behaviors this loader doesn't know; downgrading the runtime bundle while keeping a config generated by a newer SDK.
Related errors
- Can't use moduleFactory callback of createDotnetRuntime…
- Invalid config, resources is not set
- Loader configuration error: 'mainAssemblyName' is required.
- Loader configuration error: 'resources.coreAssembly' is…
- Mismatched git hashes between loader and runtime. Loader
AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10).
Data as JSON: /api/errors/e62f4a331edeeabf.
Report an issue: GitHub.
Appendix: source
Thrown at src/mono/browser/runtime/assets.ts:61
const lastSlash = virtualName.lastIndexOf("/");
let parentDirectory = (lastSlash > 0)
? virtualName.substring(0, lastSlash)
: browserVirtualAppBase;
let fileName = (lastSlash > 0)
? virtualName.substring(lastSlash + 1)
: virtualName;
if (fileName.startsWith("/"))
fileName = fileName.substring(1);
if (!parentDirectory.startsWith("/"))
parentDirectory = browserVirtualAppBase + parentDirectory;
mono_log_debug(() => `Creating file '${fileName}' in directory '${parentDirectory}'`);
Module.FS_createPath("/", parentDirectory, true, true);
Module.FS_createDataFile(parentDirectory, fileName, bytes, true /* canRead */, true /* canWrite */, true /* canOwn */);
break;
}
default:
throw new Error(`Unrecognized asset behavior:${asset.behavior}, for asset ${asset.name}`);
}
if (asset.behavior === "assembly") {
// this is reading flag inside the DLL about the existence of PDB
// it doesn't relate to whether the .pdb file is downloaded at all
const hasPdb = cwraps.mono_wasm_add_assembly(virtualName, offset!, bytes.length);
if (!hasPdb) {
const index = loaderHelpers._loaded_files.findIndex(element => element.file == virtualName);
loaderHelpers._loaded_files.splice(index, 1);
}
} else if (asset.behavior === "pdb") {
cwraps.mono_wasm_add_assembly(virtualName, offset!, bytes.length);
} else if (asset.behavior === "icu") {
wasm_load_icu_data(offset!);
} else if (asset.behavior === "resource") {
cwraps.mono_wasm_add_satellite_assembly(virtualName, asset.culture || "", offset!, bytes.length);
}View on GitHub (pinned to 60108ba66e)