{"record":{"id":"8eed72ec2b5b99b0","repo":"vuejs/vue","slug":"render-cannot-be-called-without-a-template","errorCode":null,"errorMessage":"render cannot be called without a template.","messagePattern":"render cannot be called without a template\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server-renderer/src/template-renderer/index.ts","lineNumber":113,"sourceCode":"    const renderer: any = this\n    ;['ResourceHints', 'State', 'Scripts', 'Styles'].forEach(type => {\n      context[`render${type}`] = renderer[`render${type}`].bind(\n        renderer,\n        context\n      )\n    })\n    // also expose getPreloadFiles, useful for HTTP/2 push\n    context.getPreloadFiles = renderer.getPreloadFiles.bind(renderer, context)\n  }\n\n  // render synchronously given rendered app content and render context\n  render(\n    content: string,\n    context: Record<string, any> | null\n  ): string | Promise<string> {\n    const template = this.parsedTemplate\n    if (!template) {\n      throw new Error('render cannot be called without a template.')\n    }\n    context = context || {}\n\n    if (typeof template === 'function') {\n      return template(content, context)\n    }\n\n    if (this.inject) {\n      return (\n        template.head(context) +\n        (context.head || '') +\n        this.renderResourceHints(context) +\n        this.renderStyles(context) +\n        template.neck(context) +\n        content +\n        this.renderState(context) +\n        this.renderScripts(context) +\n        template.tail(context)","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/vuejs/vue/blob/9e88707940088cb1f4cd7dd210c9168a50dc347c/packages/server-renderer/src/template-renderer/index.ts#L95-L131","documentation":"Thrown by TemplateRenderer.render when called but parsedTemplate is null — meaning the renderer was created without a template option (template was undefined/false). render() is meant to wrap rendered app content with the surrounding HTML shell; without a parsed template there is nothing to wrap with. This is usually an internal path: createRenderer calls templateRenderer.render only when template is set, so hitting this means an explicit direct call or a logic regression.","triggerScenarios":"Manually calling templateRenderer.render(content, ctx) on a renderer built without a template. Or a code path in createRenderer.renderToString that reaches templateRenderer.render despite template being falsy due to a bug or monkeypatched options.","commonSituations":"A custom integration reaches into the internal templateRenderer instance. A renderer was created for asset/preload rendering only (no template) but later used for full-page rendering. Refactor that swapped renderer instances.","solutions":["Provide a template option when creating the renderer: createRenderer({ template: '<html>...<!--vue-ssr-outlet-->...</html>' }).","If you called render() directly, guard it: if (!renderer.parsedTemplate) return content.","Use a separate renderer instance for full-page rendering vs. asset rendering."],"exampleFix":"// before\nconst renderer = createRenderer({}) // no template\nconst html = renderer.templateRenderer.render(content, ctx) // throws\n\n// after\nconst renderer = createRenderer({\n  template: '<!DOCTYPE html><html><head></head><body><!--vue-ssr-outlet--></body></html>'\n})","handlingStrategy":"validation","validationCode":"function assertTemplateSet(templateRenderer: any): void {\n  if (!templateRenderer.parsedTemplate) {\n    throw new Error(\n      'TemplateRenderer.render called without a template. Pass a template to createRenderer.'\n    )\n  }\n}\n\n// if calling render directly:\nassertTemplateSet(renderer.templateRenderer)\nrenderer.templateRenderer.render(content, ctx)","typeGuard":"function hasParsedTemplate(tr: any): boolean {\n  return tr.parsedTemplate != null\n}","tryCatchPattern":"// Internal API — prefer not to call render() directly.\n// Instead, ensure createRenderer was built with a template:\nif (!options.template) {\n  throw new Error('Cannot use full-page rendering without a template option')\n}\nconst renderer = createRenderer(options)","preventionTips":["Treat TemplateRenderer as internal; use the public createRenderer/renderToString API.","Always pass a template option when full-page SSR is needed.","Keep a single renderer instance per template configuration."],"tags":["ssr","template-renderer","template","render","internal"],"analyzedSha":"9e88707940088cb1f4cd7dd210c9168a50dc347c","analyzedAt":"2026-08-11T22:22:01.295Z","schemaVersion":2},"datasetVersion":"2026-08-12T04:17:13.124Z"}