vuejs/vue · error · Error

createStream cannot be called without a template.

Error message

createStream cannot be called without a template.

What it means

Thrown by TemplateRenderer.createStream when called without a parsedTemplate. createStream builds a TemplateStream (a Node transform stream) that wraps the rendered content with the template's head/neck/tail as data flows through; without a template there is no wrapping to do and the stream would be meaningless. This path is reached from create-renderer.ts renderToStream only when a string template is set, so a direct call or a regression triggers it.

Source

Thrown at packages/server-renderer/src/template-renderer/index.ts:275

    }
  }

  getUsedAsyncFiles(context: Record<string, any>): Array<Resource> | undefined {
    if (
      !context._mappedFiles &&
      context._registeredComponents &&
      this.mapFiles
    ) {
      const registered: any[] = Array.from(context._registeredComponents)
      context._mappedFiles = this.mapFiles(registered).map(normalizeFile)
    }
    return context._mappedFiles
  }

  // create a transform stream
  createStream(context: Record<string, any> | undefined): TemplateStream {
    if (!this.parsedTemplate) {
      throw new Error('createStream cannot be called without a template.')
    }
    //@ts-expect-error
    return new TemplateStream(this, this.parsedTemplate, context || {})
  }
}

function normalizeFile(file: string): Resource {
  const withoutQuery = file.replace(/\?.*/, '')
  const extension = path.extname(withoutQuery).slice(1)
  return {
    file,
    extension,
    fileWithoutQuery: withoutQuery,
    asType: getPreloadType(extension)
  }
}

function getPreloadType(ext: string): string {

View on GitHub (pinned to 9e88707940)

Solutions

  1. Ensure a non-empty template string is passed to createRenderer when using renderToStream with a template.
  2. Guard: if (templateRenderer.parsedTemplate) { stream = templateRenderer.createStream(ctx) } else { /* skip wrapping */ }.
  3. If no template is needed, use renderToStream without the template option — the no-template branch in create-renderer returns the raw render stream.

Example fix

// before
const renderer = createRenderer({ template: '' }) // empty
renderer.renderToStream(app) // reaches createStream with null parsedTemplate

// after
const renderer = createRenderer({
  template: '<!DOCTYPE html><html><body><!--vue-ssr-outlet--></body></html>'
})
renderer.renderToStream(app)
Defensive patterns

Strategy: validation

Validate before calling

function assertTemplateSetForStream(templateRenderer: any): void {
  if (!templateRenderer.parsedTemplate) {
    throw new Error('createStream requires a template; pass one to createRenderer.')
  }
}

assertTemplateSetForStream(renderer.templateRenderer)
renderer.renderToStream(app)

Type guard

function canCreateStream(tr: any): boolean {
  return tr.parsedTemplate != null && typeof tr.parsedTemplate !== 'function'
}

Try / catch

try {
  renderer.renderToStream(app, context)
} catch (e) {
  if (e.message.includes('createStream cannot be called without a template')) {
    // recreate renderer with a template, or use renderToString
    renderer.renderToString(app, context, cb)
  } else {
    throw e
  }
}

Prevention

When it happens

Trigger: Manually invoking templateRenderer.createStream(ctx) when the renderer was constructed without a template. Hitting the else branch in renderToStream with a truthy non-function template but parsedTemplate somehow null (e.g. template was an empty string).

Common situations: Custom streaming pipeline reaches into templateRenderer.createStream. Template was set to '' (empty string) which parseTemplate receives but indexOf falls through, or template option was explicitly null after object merge.

Related errors


AI-assisted analysis of vuejs/vue@9e88707940 (2026-08-11). Data as JSON: /api/errors/97c3fe733b9bc86d. Report an issue: GitHub.