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
- Set root: / for a site served at the domain root.
- For a sub-path install, set root: /blog/ (trailing slash).
- 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
- Use root: / for root-served sites, root: /blog/ for sub-paths.
- Never set root to an empty or whitespace string.
- Add a config sanity check to deploy scripts.
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
- Invalid config detected: "root" should be string, not ${type
- Invalid config detected: "url" should be string, not ${typeo
- Invalid config detected: "url" should be a valid URL!
- fn must be a function
- name is required
AI-assisted analysis of hexojs/hexo@059cb17494 (2026-08-12).
Data as JSON: /api/errors/61d1e167023b384f.
Report an issue: GitHub.