{"record":{"id":"68c864ba2d940cae","repo":"vuejs/vue","slug":"content-placeholder-not-found-in-template","errorCode":null,"errorMessage":"Content placeholder not found in template.","messagePattern":"Content placeholder not found in template\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server-renderer/src/template-renderer/parse-template.ts","lineNumber":25,"sourceCode":"export type ParsedTemplate = {\n  head: (data: any) => string\n  neck: (data: any) => string\n  tail: (data: any) => string\n}\n\nexport function parseTemplate(\n  template: string,\n  contentPlaceholder: string = '<!--vue-ssr-outlet-->'\n): ParsedTemplate {\n  if (typeof template === 'object') {\n    return template\n  }\n\n  let i = template.indexOf('</head>')\n  const j = template.indexOf(contentPlaceholder)\n\n  if (j < 0) {\n    throw new Error(`Content placeholder not found in template.`)\n  }\n\n  if (i < 0) {\n    i = template.indexOf('<body>')\n    if (i < 0) {\n      i = j\n    }\n  }\n\n  return {\n    head: compile(template.slice(0, i), compileOptions),\n    neck: compile(template.slice(i, j), compileOptions),\n    tail: compile(template.slice(j + contentPlaceholder.length), compileOptions)\n  }\n}\n","sourceCodeStart":7,"sourceCodeEnd":41,"githubUrl":"https://github.com/vuejs/vue/blob/9e88707940088cb1f4cd7dd210c9168a50dc347c/packages/server-renderer/src/template-renderer/parse-template.ts#L7-L41","documentation":"Thrown by parseTemplate when the template HTML does not contain the content placeholder (default: <!--vue-ssr-outlet-->). The placeholder marks where rendered app content is injected between neck and tail. Without it the template cannot be split into head/neck/tail sections. parseTemplate is called once during TemplateRenderer construction when a string template is provided.","triggerScenarios":"Passing createRenderer a template string that lacks the <!--vue-ssr-outlet--> marker (or whatever custom contentPlaceholder was configured). The indexOf check returns -1 and the error fires immediately at renderer creation.","commonSituations":"Copy-pasting an HTML shell from a non-Vue project that omits the placeholder. Renaming or removing the placeholder by mistake. Using {{{app}}} or {{content}} (other frameworks' syntax) instead of the Vue SSR marker. A minifier or HTML processor stripped HTML comments including the placeholder.","solutions":["Add <!--vue-ssr-outlet--> inside the <body> of the template HTML where app content should appear.","If using a custom placeholder, pass it as the contentPlaceholder argument to parseTemplate (note: createRenderer does not expose this, so the default marker is effectively required).","Ensure HTML minifiers preserve comments or run after the template is parsed.","If the template is an object/function (programmatic), parseTemplate returns it as-is and this check is skipped."],"exampleFix":"<!-- before -->\n<!DOCTYPE html>\n<html>\n  <body>\n    <div id=\"app\"></div>\n  </body>\n</html>\n\n<!-- after -->\n<!DOCTYPE html>\n<html>\n  <body>\n    <!--vue-ssr-outlet-->\n  </body>\n</html>","handlingStrategy":"validation","validationCode":"const PLACEHOLDER = '<!--vue-ssr-outlet-->'\n\nfunction templateHasPlaceholder(template: string, placeholder = PLACEHOLDER): boolean {\n  return template.indexOf(placeholder) >= 0\n}\n\nif (typeof options.template === 'string' && !templateHasPlaceholder(options.template)) {\n  throw new Error(\n    `SSR template must contain ${PLACEHOLDER} where app content should be injected.`\n  )\n}\ncreateRenderer(options)","typeGuard":"function isValidSsrTemplate(t: unknown): boolean {\n  return typeof t === 'string' && t.includes('<!--vue-ssr-outlet-->')\n}","tryCatchPattern":"try {\n  createRenderer({ template })\n} catch (e) {\n  if (e.message.includes('Content placeholder not found')) {\n    template = template.replace('<div id=\"app\"></div>', '<!--vue-ssr-outlet-->')\n    createRenderer({ template })\n  } else {\n    throw e\n  }\n}","preventionTips":["Always include <!--vue-ssr-outlet--> in the SSR template HTML inside <body>.","Configure HTML minifiers to preserve comments (html-minifier: collapseWhitespace with removeComments=false).","Store the template as a checked constant rather than inline string to avoid drift.","Add a startup test that asserts the template contains the placeholder."],"tags":["ssr","template","placeholder","html","parse"],"analyzedSha":"9e88707940088cb1f4cd7dd210c9168a50dc347c","analyzedAt":"2026-08-11T22:22:01.295Z","schemaVersion":2},"datasetVersion":"2026-08-12T05:08:24.936Z"}