vitejs/vite · error · Error

{ runtime: "${result.runtime}" } is not supported for assets

Error message

{ runtime: "${result.runtime}" } is not supported for assets in ${hostType} files: ${filename}

What it means

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.

Source

Thrown at packages/plugin-legacy/src/index.ts:81

  filename: string,
  type: 'asset' | 'public',
  hostId: string,
  hostType: 'js' | 'css' | 'html',
  config: ResolvedConfig,
  toRelative: (filename: string, importer: string) => string,
): string {
  const { renderBuiltUrl } = config.experimental
  let relative = config.base === '' || config.base === './'
  if (renderBuiltUrl) {
    const result = renderBuiltUrl(filename, {
      hostId,
      hostType,
      type,
      ssr: !!config.build.ssr,
    })
    if (typeof result === 'object') {
      if (result.runtime) {
        throw new Error(
          `{ runtime: "${result.runtime}" } is not supported for assets in ${hostType} files: ${filename}`,
        )
      }
      if (typeof result.relative === 'boolean') {
        relative = result.relative
      }
    } else if (result) {
      return result
    }
  }
  if (relative && !config.build.ssr) {
    return toRelative(filename, hostId)
  } else {
    // @ts-expect-error `decodedBase` is internal
    return joinUrlSegments(config.decodedBase, filename)
  }
}
function getBaseInHTML(urlRelativePath: string, config: ResolvedConfig) {

View on GitHub (pinned to 89620f09af)

Solutions

  1. 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'.
  2. 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.
  3. If runtime resolution in HTML is genuinely needed, inline a <script> that sets window-level base before asset tags rather than using renderBuiltUrl.

Example fix

// before
renderBuiltUrl(filename) {
  return { runtime: `window.__CDN__ + ${JSON.stringify(filename)}` }
}
// after
renderBuiltUrl(filename, { hostType }) {
  if (hostType === 'js' || hostType === 'css') {
    return { runtime: `window.__CDN__ + ${JSON.stringify(filename)}` }
  }
  return undefined // let plugin-legacy handle html assets normally
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate renderBuiltUrl return before it reaches plugin-legacy
function safeRenderBuiltUrl(filename, { hostType }) {
  const result = myRenderBuiltUrl(filename, { hostType })
  if (
    typeof result === 'object' &&
    result?.runtime &&
    hostType === 'html'
  ) {
    console.warn(`renderBuiltUrl: runtime not supported for html assets, falling back for ${filename}`)
    return undefined
  }
  return result
}

Type guard

function isHtmlSafeRenderResult(
  result: unknown,
  hostType: string
): result is string | { relative?: boolean } | undefined {
  if (result == null || typeof result === 'string') return true
  if (typeof result === 'object') {
    if (hostType === 'html' && 'runtime' in result && result.runtime) return false
    return true
  }
  return false
}

Try / catch

// Wrap the vite.config export to validate at config resolution time
try {
  const cfg = defineConfig({
    experimental: {
      renderBuiltUrl(filename, ctx) {
        const result = customUrlFn(filename, ctx)
        if (ctx.hostType === 'html' && typeof result === 'object' && result?.runtime) {
          throw new Error(`runtime not supported for html asset: ${filename}`)
        }
        return result
      }
    }
  })
} catch (e) {
  console.error('renderBuiltUrl config error:', e.message)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/b079207d28ff8f6a.json. Report an issue: GitHub.