{"id":"b079207d28ff8f6a","repo":"vitejs/vite","slug":"runtime-result-runtime-is-not-supported","errorCode":null,"errorMessage":"{ runtime: \"${result.runtime}\" } is not supported for assets in ${hostType} files: ${filename}","messagePattern":"(.+?) is not supported for assets in (.+?) files: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugin-legacy/src/index.ts","lineNumber":81,"sourceCode":"  filename: string,\n  type: 'asset' | 'public',\n  hostId: string,\n  hostType: 'js' | 'css' | 'html',\n  config: ResolvedConfig,\n  toRelative: (filename: string, importer: string) => string,\n): string {\n  const { renderBuiltUrl } = config.experimental\n  let relative = config.base === '' || config.base === './'\n  if (renderBuiltUrl) {\n    const result = renderBuiltUrl(filename, {\n      hostId,\n      hostType,\n      type,\n      ssr: !!config.build.ssr,\n    })\n    if (typeof result === 'object') {\n      if (result.runtime) {\n        throw new Error(\n          `{ runtime: \"${result.runtime}\" } is not supported for assets in ${hostType} files: ${filename}`,\n        )\n      }\n      if (typeof result.relative === 'boolean') {\n        relative = result.relative\n      }\n    } else if (result) {\n      return result\n    }\n  }\n  if (relative && !config.build.ssr) {\n    return toRelative(filename, hostId)\n  } else {\n    // @ts-expect-error `decodedBase` is internal\n    return joinUrlSegments(config.decodedBase, filename)\n  }\n}\nfunction getBaseInHTML(urlRelativePath: string, config: ResolvedConfig) {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/vitejs/vite/blob/89620f09afcfef6b35e7bb8660132ab5b4d0cd3b/packages/plugin-legacy/src/index.ts#L63-L99","documentation":"Thrown by @vitejs/plugin-legacy's internal toOutputFilePathInHtml when the experimental.renderBuiltUrl hook returns an object containing a `runtime` property for an asset referenced inside an HTML file. While `{ runtime }` is a valid return for JS/CSS hosts (Vite core emits it as a runtime-evaluated expression), HTML files cannot execute arbitrary runtime expressions to resolve asset URLs, so plugin-legacy explicitly rejects it. This is a deliberate constraint of the legacy plugin's duplicated HTML path resolver.","triggerScenarios":"Configuring experimental.renderBuiltUrl in vite.config to return { runtime: '...' } unconditionally for every asset, regardless of hostType. Specifically when the hostType is 'html' (i.e., assets referenced in index.html) and the callback does not branch on the hostType/type arguments passed to it.","commonSituations":"A developer adds experimental.renderBuiltUrl to dynamically rewrite CDN or base URLs at runtime. They return { runtime: 'window.__ASSET_BASE__ + \"...\"' } for all files without checking the hostType. This works for JS chunks (handled by Vite core's toOutputFilePathInJS at build.ts:1667) but breaks when plugin-legacy processes the same assets inside HTML templates.","solutions":["In your renderBuiltUrl callback, check the hostType argument and only return { runtime } when hostType is 'js' or 'css'; return a plain string or { relative } for 'html'.","If you only need runtime resolution for JS chunks, guard the callback with `if (type.hostType === 'html') return undefined` to fall back to default HTML asset path resolution.","If runtime resolution in HTML is genuinely needed, inline a <script> that sets window-level base before asset tags rather than using renderBuiltUrl."],"exampleFix":"// before\nrenderBuiltUrl(filename) {\n  return { runtime: `window.__CDN__ + ${JSON.stringify(filename)}` }\n}\n// after\nrenderBuiltUrl(filename, { hostType }) {\n  if (hostType === 'js' || hostType === 'css') {\n    return { runtime: `window.__CDN__ + ${JSON.stringify(filename)}` }\n  }\n  return undefined // let plugin-legacy handle html assets normally\n}","handlingStrategy":"validation","validationCode":"// Validate renderBuiltUrl return before it reaches plugin-legacy\nfunction safeRenderBuiltUrl(filename, { hostType }) {\n  const result = myRenderBuiltUrl(filename, { hostType })\n  if (\n    typeof result === 'object' &&\n    result?.runtime &&\n    hostType === 'html'\n  ) {\n    console.warn(`renderBuiltUrl: runtime not supported for html assets, falling back for ${filename}`)\n    return undefined\n  }\n  return result\n}","typeGuard":"function isHtmlSafeRenderResult(\n  result: unknown,\n  hostType: string\n): result is string | { relative?: boolean } | undefined {\n  if (result == null || typeof result === 'string') return true\n  if (typeof result === 'object') {\n    if (hostType === 'html' && 'runtime' in result && result.runtime) return false\n    return true\n  }\n  return false\n}","tryCatchPattern":"// Wrap the vite.config export to validate at config resolution time\ntry {\n  const cfg = defineConfig({\n    experimental: {\n      renderBuiltUrl(filename, ctx) {\n        const result = customUrlFn(filename, ctx)\n        if (ctx.hostType === 'html' && typeof result === 'object' && result?.runtime) {\n          throw new Error(`runtime not supported for html asset: ${filename}`)\n        }\n        return result\n      }\n    }\n  })\n} catch (e) {\n  console.error('renderBuiltUrl config error:', e.message)\n}","preventionTips":["Always branch on hostType in renderBuiltUrl and only return { runtime } for 'js'/'css'.","Write a unit test that calls renderBuiltUrl with every hostType value to catch regressions.","Review the RenderBuiltAssetUrl type signature — runtime is allowed by the type but not by all hosts."],"tags":["plugin-legacy","render-built-url","html-assets","config"],"analyzedSha":"89620f09afcfef6b35e7bb8660132ab5b4d0cd3b","analyzedAt":"2026-08-03T19:28:02.920Z","schemaVersion":2}