hexojs/hexo · error · Error
Partial ${name} does not exist. (in ${currentView})
Error message
Partial ${name} does not exist. (in ${currentView}) What it means
Hexo's `partial` helper renders a sub-template from the active theme's view registry. It resolves `name` first relative to the current view's directory (`join(dirname(currentView), name)`), then falls back to the bare `name`, both via `ctx.theme.getView()`. If neither lookup returns a registered view, Hexo throws — it cannot render a partial it cannot find in the theme. The message includes `currentView` to show which template made the failing call.
Source
Thrown at lib/plugins/helper/partial.ts:20
import type Hexo from '../../hexo';
import type { LocalsType } from '../../types';
interface Options {
cache?: boolean | string;
only?: boolean;
}
export = (ctx: Hexo) => function partial(this: LocalsType, name: string, locals?: any, options: Options = {}) {
if (typeof name !== 'string') throw new TypeError('name must be a string!');
const { cache } = options;
const viewDir = this.view_dir;
const currentView = this.filename.substring(viewDir.length);
const path = join(dirname(currentView), name);
const view = ctx.theme.getView(path) || ctx.theme.getView(name);
if (!view) {
throw new Error(`Partial ${name} does not exist. (in ${currentView})`);
}
// Build locals lazily so a fragment cache hit does not copy the render context.
const render = () => {
const viewLocals: Record<string, any> = {};
if (options.only) {
Object.assign(viewLocals, locals);
} else {
Object.assign(viewLocals, this, locals);
}
// Partial don't need layout
viewLocals.layout = false;
return view.renderSync(viewLocals);
};
View on GitHub (pinned to 059cb17494)
Solutions
- Confirm the partial file exists in the theme's `layout/` directory at the path Hexo resolves (account for the dirname-relative join: from `layout/post.ejs`, `partial('foo')` looks for `layout/post/foo`).
- Anchor the path explicitly: use `partial('_partial/share')` from a top-level layout, or `partial('../_partial/share')` when calling from a nested directory.
- Verify the file extension matches a renderer Hexo has loaded (.ejs / .njk / .pug) so `getView()` actually registers it.
- Check `_config.yml` `theme:` points to the installed theme that contains the partial.
Example fix
// before (called from layout/post.ejs -> resolves to layout/post/share)
<%- partial('share') %>
// after (anchored to the theme partial folder)
<%- partial('_partial/share') %>
// or, from a nested layout
<%- partial('../_partial/share') %> Defensive patterns
Strategy: validation
Validate before calling
// Before rendering a layout that uses partial(), confirm the file is registered.
// Hexo resolves `partial(name)` relative to the calling view's directory first,
// then as a bare name. Check both candidate paths on disk:
const path = require('path');
const fs = require('fs');
function partialExists(themeDir, currentLayoutFile, name) {
const rendererExt = ['.ejs', '.njk', '.pug', '.swig', '.hbs']; // adjust to loaded renderers
const dir = path.dirname(currentLayoutFile);
const candidates = [
path.join(themeDir, 'layout', dir, name),
path.join(themeDir, 'layout', name)
];
return candidates.some(p =>
rendererExt.some(ext => fs.existsSync(p + ext))
);
}
// usage
if (!partialExists(hexo.theme_dir, 'post.ejs', '_partial/share')) {
hexo.log.warn('Missing partial _partial/share');
} Type guard
const isPartialName = (s: unknown): s is string =>
typeof s === 'string' && s.trim().length > 0 && !s.includes(' ');
// usage before calling partial():
// if (!isPartialName(name)) throw new Error('invalid partial name'); Try / catch
// Wrap render in a script that treats a missing partial as non-fatal.
try {
return hexo.theme.getView(name)?.renderSync(locals) ?? '';
} catch (e) {
if (e instanceof Error && /Partial .* does not exist/.test(e.message)) {
hexo.log.warn(`Skipping missing partial: ${e.message}`);
return '';
}
throw e;
} Prevention
- Keep all partials under layout/_partial/ and always reference them as `_partial/<name>` to avoid dirname-relative surprises.
- Add a CI check that greps templates for `partial(...)` calls and asserts each resolves to a file under `layout/`.
- After switching themes, run `hexo clean && hexo generate` so the view registry is rebuilt.
- Use consistent template extensions across the theme so getView() registers every file.
When it happens
Trigger: Calling `<%- partial('share') %>` (or `partial('_partial/foo')`) in a layout/partial when no file `share.*` / `_partial/foo.*` exists in the theme's `layout` directory at the resolved path. Because the path is joined with `dirname(currentView)`, a call from `layout/post.ejs` with name `foo` looks for `layout/post/foo`, not `layout/foo`.
Common situations: Typo in the partial name; forgetting the `_partial/` prefix; calling a partial from a nested layout without `../` anchoring; theme not installed or wrong `theme:` in `_config.yml`; renderer extension mismatch (theme is .njk but only a .ejs file exists); partial file added but not under `layout/`.
Related errors
- name must be a string!
- start_color is required!
- end_color is required!
- name is required
- name is required
AI-assisted analysis of hexojs/hexo@059cb17494 (2026-08-12).
Data as JSON: /api/errors/26f90c73061198bf.
Report an issue: GitHub.