dotnet/AspNetCore.Docs · error · Error

${this.type} `template` option must consist of exactly 1 top

Error message

${this.type} `template` option must consist of exactly 1 top-level element!

What it means

Bootstrap 3.3.7's Tooltip.prototype.tip() builds its DOM node by running the `template` option through jQuery's $(). It requires the result to contain exactly one top-level element (this.$tip.length === 1). Anything else — empty, multiple siblings, or a bare selector — is treated as a misconfiguration and throws on first show. The `${this.type}` prefix is the plugin name ("tooltip" or "popover"), since Popover extends Tooltip.

Source

Thrown at aspnetcore/mvc/controllers/testing/samples/2.x/TestingControllersSample/src/TestingControllersSample/wwwroot/js/bootstrap.js:1690

      var o  = this.options
  
      title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
  
      return title
    }
  
    Tooltip.prototype.getUID = function (prefix) {
      do prefix += ~~(Math.random() * 1000000)
      while (document.getElementById(prefix))
      return prefix
    }
  
    Tooltip.prototype.tip = function () {
      if (!this.$tip) {
        this.$tip = $(this.options.template)
        if (this.$tip.length != 1) {
          throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
        }
      }
      return this.$tip
    }
  
    Tooltip.prototype.arrow = function () {
      return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
    }
  
    Tooltip.prototype.enable = function () {
      this.enabled = true
    }
  
    Tooltip.prototype.disable = function () {
      this.enabled = false
    }
  
    Tooltip.prototype.toggleEnabled = function () {

View on GitHub (pinned to c67a80103a)

Solutions

  1. Make the template a single rooted HTML element string, e.g. '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'.
  2. Do not pass a CSS selector as `template`; it is interpreted as HTML by jQuery and may match 0 or many nodes.
  3. If overriding per-instance, validate the string has exactly one root before passing it.
  4. If you don't need a custom template, remove the option entirely to use Bootstrap's built-in default.

Example fix

// before
$('#el').tooltip({ template: '<div class="tip"></div><span class="extra"></span>' });
// after
$('#el').tooltip({ template: '<div class="tip" role="tooltip"><div class="tooltip-inner"></div></div>' });
Defensive patterns

Strategy: validation

Validate before calling

// Validate a Bootstrap template string has exactly one top-level element before init.
function isValidTooltipTemplate(tpl) {
  if (typeof tpl !== 'string' || tpl.trim() === '') return false;
  var nodes = $(tpl);
  return nodes.length === 1 && nodes[0].nodeType === 1;
}
var tpl = options && options.template;
if (tpl && !isValidTooltipTemplate(tpl)) {
  console.warn('Refusing to init tooltip: template is not a single top-level element');
  delete options.template;
}
$('#el').tooltip(options);

Type guard

function isSingleElementTemplate(tpl) {
  return typeof tpl === 'string' && $(tpl).length === 1;
}

Try / catch

try {
  $('#el').tooltip({ template: customTpl });
} catch (e) {
  if (/template.*1 top-level element/.test(e.message)) {
    console.error('Bad tooltip template, falling back to default', customTpl);
    $('#el').tooltip({}); // default template
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling $('#el').tooltip({template: '...'}) or .popover({template: '...'}) where the string yields zero or 2+ top-level nodes; passing a CSS selector like '.my-tip' instead of HTML; an empty string; HTML with leading text siblings like 'x<div></div>'.

Common situations: Customizing tooltip markup; copying a template from another Bootstrap version whose default differs; bundler mangling the string; leaving a half-edited default template.

Related errors


AI-assisted analysis of dotnet/AspNetCore.Docs@c67a80103a (2026-08-13). Data as JSON: /api/errors/0e032a9434dd2a20. Report an issue: GitHub.