dotnet/aspnetcore · error · Error
For a resource, custom loaders must supply a URI string.
Error message
For a ${resourceType} resource, custom loaders must supply a URI string. What it means
When a `loadBootResource` callback is supplied, Blazor lets it override the URL for the `dotnetjs` (the runtime JS module) resource. Because the runtime JS must be loaded via a dynamic `import()`, the custom loader can only return a URI string — any other truthy return (e.g. a `Request`/`Response`/`URL`) is unusable for a module import and throws.
Solutions
- For `resourceType === 'dotnetjs'`, return a string URL (or `null` to use the default) from `loadBootResource` — never a Request/Response.
- Branch your `loadBootResource` by resource type so only fetchable resources use the richer return shapes.
- If you don't need to override the runtime JS URL, return `null`/`undefined` for `dotnetjs`.
- Coerce with `String(customSrc)` or construct via `new URL(...).toString()` before returning.
Example fix
// before
loadBootResource: (type, name) => new Request(`/cdn/${name}`) // throws for dotnetjs
// after
loadBootResource: (type, name) =>
type === 'dotnetjs' ? `/cdn/${name}` : new Request(`/cdn/${name}`) Defensive patterns
Strategy: validation
Validate before calling
loadBootResource: (type, name, defaultUri) => {
if (type === 'dotnetjs') return typeof customSrc === 'string' ? customSrc : null;
return customSrc; // Request/Response ok for other types
} Type guard
function isUriString(v: unknown): v is string { return typeof v === 'string'; } Try / catch
try { await Blazor.start({ loadBootResource }); }
catch (e) { if (/must supply a URI string/.test(e.message)) { /* fix loader for dotnetjs */ } throw e; } Prevention
- Branch loadBootResource by resourceType.
- Return only a string (or null) for the dotnetjs resource.
- Coerce URLs with new URL(...).toString() before returning.
- Reuse null/undefined to opt out for resources you don't override.
When it happens
Trigger: Supplying `loadBootResource` in `Blazor.start({ loadBootResource })` and, for a `dotnetjs` resource, returning a truthy non-string value (Request, Response, URL object, or similar).
Common situations: Reusing a generic `loadBootResource` implementation (that returns `Request`/`Response` for fetchable assets) for every resource type without special-casing `dotnetjs`; caching/proxying logic returning a URL object instead of a string; copy-pasting a loader that works for `assembly`/`pdb` but not `dotnetjs`.
Related errors
- The runtime must be loaded before it gets configured.
- This browser does not support WebAssembly.
- assembly must be defined when using a descriptor.
- Could not find any element matching selector
- Could not find checksum for
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/4598b3ab9c1c1179.
Report an issue: GitHub.
Appendix: source
Thrown at src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts:137
};
async function importDotnetJs(startOptions: Partial<WebAssemblyStartOptions>): Promise<ModuleAPI> {
const browserSupportsNativeWebAssembly = typeof WebAssembly !== 'undefined' && WebAssembly.validate;
if (!browserSupportsNativeWebAssembly) {
throw new Error('This browser does not support WebAssembly.');
}
// Allow overriding the URI from which the dotnet.*.js file is loaded
if (startOptions.loadBootResource) {
const resourceType: WebAssemblyBootResourceType = 'dotnetjs';
const customSrc = startOptions.loadBootResource(resourceType, 'dotnet.js', '_framework/dotnet.js', '', 'js-module-dotnet');
if (typeof (customSrc) === 'string') {
const absoluteSrc = (new URL(customSrc, document.baseURI)).toString();
return await import(/* webpackIgnore: true */ absoluteSrc);
} else if (customSrc) {
// Since we must load this via a import, it's only valid to supply a URI (and not a Request, say)
throw new Error(`For a ${resourceType} resource, custom loaders must supply a URI string.`);
}
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: This dynamic import is handled at runtime and does not need a type declaration.
return await import(/* webpackIgnore: true */ './dotnet.js');
}
function prepareRuntimeConfig(options: Partial<WebAssemblyStartOptions>, onConfigLoadedCallback?: (loadedConfig: MonoConfig) => void): DotnetModuleConfig {
const config: MonoConfig = {
maxParallelDownloads: 1000000, // disable throttling parallel downloads
enableDownloadRetry: false, // disable retry downloads
};
if (options.environment) {
config.applicationEnvironment = options.environment;
}
View on GitHub (pinned to 3600ca084e)