{"record":{"id":"4598b3ab9c1c1179","repo":"dotnet/aspnetcore","slug":"for-a-resourcetype-resource-custom-loaders-mus","errorCode":null,"errorMessage":"For a ${resourceType} resource, custom loaders must supply a URI string.","messagePattern":"For a (.+?) resource, custom loaders must supply a URI string\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts","lineNumber":137,"sourceCode":"};\n\nasync function importDotnetJs(startOptions: Partial<WebAssemblyStartOptions>): Promise<ModuleAPI> {\n  const browserSupportsNativeWebAssembly = typeof WebAssembly !== 'undefined' && WebAssembly.validate;\n  if (!browserSupportsNativeWebAssembly) {\n    throw new Error('This browser does not support WebAssembly.');\n  }\n\n\n  // Allow overriding the URI from which the dotnet.*.js file is loaded\n  if (startOptions.loadBootResource) {\n    const resourceType: WebAssemblyBootResourceType = 'dotnetjs';\n    const customSrc = startOptions.loadBootResource(resourceType, 'dotnet.js', '_framework/dotnet.js', '', 'js-module-dotnet');\n    if (typeof (customSrc) === 'string') {\n      const absoluteSrc = (new URL(customSrc, document.baseURI)).toString();\n      return await import(/* webpackIgnore: true */ absoluteSrc);\n    } else if (customSrc) {\n      // Since we must load this via a import, it's only valid to supply a URI (and not a Request, say)\n      throw new Error(`For a ${resourceType} resource, custom loaders must supply a URI string.`);\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n  // @ts-ignore: This dynamic import is handled at runtime and does not need a type declaration.\n  return await import(/* webpackIgnore: true */ './dotnet.js');\n}\n\nfunction prepareRuntimeConfig(options: Partial<WebAssemblyStartOptions>, onConfigLoadedCallback?: (loadedConfig: MonoConfig) => void): DotnetModuleConfig {\n  const config: MonoConfig = {\n    maxParallelDownloads: 1000000, // disable throttling parallel downloads\n    enableDownloadRetry: false, // disable retry downloads\n  };\n\n  if (options.environment) {\n    config.applicationEnvironment = options.environment;\n  }\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Platform/Mono/MonoPlatform.ts#L119-L155","documentation":"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.","triggerScenarios":"Supplying `loadBootResource` in `Blazor.start({ loadBootResource })` and, for a `dotnetjs` resource, returning a truthy non-string value (Request, Response, URL object, or similar).","commonSituations":"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`.","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."],"exampleFix":"// before\nloadBootResource: (type, name) => new Request(`/cdn/${name}`) // throws for dotnetjs\n\n// after\nloadBootResource: (type, name) =>\n  type === 'dotnetjs' ? `/cdn/${name}` : new Request(`/cdn/${name}`)","handlingStrategy":"validation","validationCode":"loadBootResource: (type, name, defaultUri) => {\n  if (type === 'dotnetjs') return typeof customSrc === 'string' ? customSrc : null;\n  return customSrc; // Request/Response ok for other types\n}","typeGuard":"function isUriString(v: unknown): v is string { return typeof v === 'string'; }","tryCatchPattern":"try { await Blazor.start({ loadBootResource }); }\ncatch (e) { if (/must supply a URI string/.test(e.message)) { /* fix loader for dotnetjs */ } throw e; }","preventionTips":["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."],"tags":["webassembly","blazor-wasm","loadbootresource","config","startup"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}