hexojs/hexo · error · TypeError

end_color is required!

Error message

end_color is required!

What it means

Hexo's `tagcloud` helper (alias `tag_cloud`) renders a tag cloud. When `color: true` is set, it interpolates each tag's color along a gradient between `start_color` and `end_color` using the `Color` class (`startColor.mix(endColor, ratio)`). Both endpoints are mandatory whenever color is enabled, so Hexo throws `TypeError('end_color is required!')` if `end_color` is missing while `color` is truthy. The check runs immediately after the `start_color` check, so both messages can appear in sequence only if the first is fixed.

Source

Thrown at lib/plugins/helper/tagcloud.ts:51

  const min = options.min_font || 10;
  const max = options.max_font || 20;
  const orderby = options.orderby || 'name';
  const order = options.order || 1;
  const unit = options.unit || 'px';
  const color = options.color;
  const className = options.class;
  const showCount = options.show_count;
  const countClassName = options.count_class || 'count';
  const level = options.level || 10;
  const { transform } = options;
  const separator = options.separator || ' ';
  const result = [];
  let startColor, endColor;

  if (color) {
    if (!options.start_color) throw new TypeError('start_color is required!');
    if (!options.end_color) throw new TypeError('end_color is required!');

    startColor = new Color(options.start_color);
    endColor = new Color(options.end_color);
  }

  // Sort the tags
  if (orderby === 'random' || orderby === 'rand') {
    tags = tags.random();
  } else {
    tags = tags.sort(orderby, order);
  }

  // Limit the number of tags
  if (options.amount) {
    tags = tags.limit(options.amount);
  }

  const sizes = [];

View on GitHub (pinned to 059cb17494)

Solutions

  1. Supply `end_color` as a CSS color string together with `start_color`, e.g. `tagcloud({color: true, start_color: '#cccccc', end_color: '#333333'})`.
  2. If you do not want a gradient, remove `color: true` entirely so the color branch is skipped.

Example fix

// before
<%- tagcloud({ color: true, start_color: '#cccccc' }) %>

// after
<%- tagcloud({ color: true, start_color: '#cccccc', end_color: '#333333' }) %>
Defensive patterns

Strategy: validation

Validate before calling

// Validate tagcloud options before passing them to the helper.
function validateTagcloudOptions(o = {}) {
  if (o.color) {
    if (!o.start_color) throw new TypeError('start_color is required when color is enabled');
    if (!o.end_color) throw new TypeError('end_color is required when color is enabled');
  }
  return o;
}

// usage in a template-prep script:
const opts = validateTagcloudOptions({ color: true, start_color: '#ccc' });

Type guard

interface TagcloudOpts {
  color?: boolean;
  start_color?: string;
  end_color?: string;
  [k: string]: unknown;
}

function hasCompleteColorPair(o: TagcloudOpts): boolean {
  return !o.color || (typeof o.start_color === 'string' && typeof o.end_color === 'string'
    && o.start_color.length > 0 && o.end_color.length > 0);
}

// usage
if (!hasCompleteColorPair(opts)) { /* surface a config error early */ }

Try / catch

try {
  return tagcloud(opts);
} catch (e) {
  if (e instanceof TypeError && /end_color is required/.test(e.message)) {
    hexo.log.warn('tagcloud: color enabled without end_color; disabling color');
    return tagcloud({ ...opts, color: false });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `<%- tagcloud({color: true, start_color: '#fff'}) %>` (or `tag_cloud(...)`) with `color: true` and `start_color` present but `end_color` omitted. The guard is `if (color) { ... if (!options.end_color) throw ... }`.

Common situations: Configuring a gradient and forgetting the second endpoint; YAML indentation that drops `end_color` out of the options object; setting `end_color` to an empty string (falsy and rejected); partial copy-paste of a color config.

Related errors


AI-assisted analysis of hexojs/hexo@059cb17494 (2026-08-12). Data as JSON: /api/errors/63a8a2a07706d431. Report an issue: GitHub.