{"record":{"id":"97c3fe733b9bc86d","repo":"vuejs/vue","slug":"createstream-cannot-be-called-without-a-template","errorCode":null,"errorMessage":"createStream cannot be called without a template.","messagePattern":"createStream cannot be called without a template\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server-renderer/src/template-renderer/index.ts","lineNumber":275,"sourceCode":"    }\n  }\n\n  getUsedAsyncFiles(context: Record<string, any>): Array<Resource> | undefined {\n    if (\n      !context._mappedFiles &&\n      context._registeredComponents &&\n      this.mapFiles\n    ) {\n      const registered: any[] = Array.from(context._registeredComponents)\n      context._mappedFiles = this.mapFiles(registered).map(normalizeFile)\n    }\n    return context._mappedFiles\n  }\n\n  // create a transform stream\n  createStream(context: Record<string, any> | undefined): TemplateStream {\n    if (!this.parsedTemplate) {\n      throw new Error('createStream cannot be called without a template.')\n    }\n    //@ts-expect-error\n    return new TemplateStream(this, this.parsedTemplate, context || {})\n  }\n}\n\nfunction normalizeFile(file: string): Resource {\n  const withoutQuery = file.replace(/\\?.*/, '')\n  const extension = path.extname(withoutQuery).slice(1)\n  return {\n    file,\n    extension,\n    fileWithoutQuery: withoutQuery,\n    asType: getPreloadType(extension)\n  }\n}\n\nfunction getPreloadType(ext: string): string {","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/vuejs/vue/blob/9e88707940088cb1f4cd7dd210c9168a50dc347c/packages/server-renderer/src/template-renderer/index.ts#L257-L293","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure a non-empty template string is passed to createRenderer when using renderToStream with a template.","Guard: if (templateRenderer.parsedTemplate) { stream = templateRenderer.createStream(ctx) } else { /* skip wrapping */ }.","If no template is needed, use renderToStream without the template option — the no-template branch in create-renderer returns the raw render stream."],"exampleFix":"// before\nconst renderer = createRenderer({ template: '' }) // empty\nrenderer.renderToStream(app) // reaches createStream with null parsedTemplate\n\n// after\nconst renderer = createRenderer({\n  template: '<!DOCTYPE html><html><body><!--vue-ssr-outlet--></body></html>'\n})\nrenderer.renderToStream(app)","handlingStrategy":"validation","validationCode":"function assertTemplateSetForStream(templateRenderer: any): void {\n  if (!templateRenderer.parsedTemplate) {\n    throw new Error('createStream requires a template; pass one to createRenderer.')\n  }\n}\n\nassertTemplateSetForStream(renderer.templateRenderer)\nrenderer.renderToStream(app)","typeGuard":"function canCreateStream(tr: any): boolean {\n  return tr.parsedTemplate != null && typeof tr.parsedTemplate !== 'function'\n}","tryCatchPattern":"try {\n  renderer.renderToStream(app, context)\n} catch (e) {\n  if (e.message.includes('createStream cannot be called without a template')) {\n    // recreate renderer with a template, or use renderToString\n    renderer.renderToString(app, context, cb)\n  } else {\n    throw e\n  }\n}","preventionTips":["Pass a non-empty string template to createRenderer when using renderToStream with wrapping.","Validate the template option is a non-empty string before renderer creation.","Do not pass an empty string as template; use undefined to disable wrapping."],"tags":["ssr","template-renderer","streaming","template","internal"],"analyzedSha":"9e88707940088cb1f4cd7dd210c9168a50dc347c","analyzedAt":"2026-08-11T22:22:01.295Z","schemaVersion":2},"datasetVersion":"2026-08-12T04:17:13.124Z"}