hexojs/hexo · critical · TypeError

Invalid config detected: "root" should not be empty!

Error message

Invalid config detected: "root" should not be empty!

What it means

Thrown by validate_config (lib/hexo/validate_config.ts:26). config.root is a string but trims to zero length (empty or only whitespace). root is used to build every asset URL, so an empty value is rejected.

Source

Thrown at lib/hexo/validate_config.ts:26

  log.info('Validating config');

  // Validation for config.url && config.root
  if (typeof config.url !== 'string') {
    throw new TypeError(`Invalid config detected: "url" should be string, not ${typeof config.url}!`);
  }
  try {
    // eslint-disable-next-line no-new
    new URL(config.url);
    assert(new URL(config.url).protocol.startsWith('http'));
  } catch {
    throw new TypeError('Invalid config detected: "url" should be a valid URL!');
  }

  if (typeof config.root !== 'string') {
    throw new TypeError(`Invalid config detected: "root" should be string, not ${typeof config.root}!`);
  }
  if (config.root.trim().length <= 0) {
    throw new TypeError('Invalid config detected: "root" should not be empty!');
  }

  if (!config.timezone) {
    log.warn('No timezone setting detected! Using LocalTimeZone as the default timezone.');
    log.warn('This behavior will be changed to UTC in the next major version. Please set timezone explicitly (e.g. LocalTimeZone or America/New_York) in _config.yml to avoid this warning.');
  } else {
    const configTimezone = moment.tz.zone(config.timezone);
    if (!configTimezone) {
      log.warn(
        `Invalid timezone setting detected! "${config.timezone}" is not a valid timezone.`
      );
    } else {
      const machineTimezone = moment.tz.guess();
      if (configTimezone.name !== machineTimezone) {
        log.warn(
          `The timezone "${config.timezone}" setting is different from your machine timezone "${machineTimezone}". Make sure this is intended.`
        );
      }

View on GitHub (pinned to 059cb17494)

Solutions

  1. Set root: / for a site served at the domain root.
  2. For a sub-path install, set root: /blog/ (trailing slash).
  3. Remove any whitespace-only value.

Example fix

# before
root: ''

# after
root: /
Defensive patterns

Strategy: validation

Validate before calling

if (typeof hexo.config.root !== 'string' || hexo.config.root.trim().length === 0) {
  throw new Error("_config.yml 'root' must not be empty");
}

Prevention

When it happens

Trigger: root: '' (empty quoted string), root: ' ' (whitespace only), or root: ~ rendered as empty. A single '/' is fine because it is non-empty after trim.

Common situations: Setting root to an empty string by mistake; YAML quoting an empty value; a config merge/override clearing root; copy-paste error leaving root blank.

Related errors


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