facebook/docusaurus · error · Error
Sidebar category ${item.label} has neither any subitem nor a
Error message
Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything. What it means
Thrown by postProcessSidebarItem() during the sidebar post-processing pass. A category item that has zero children AND no link cannot navigate to anything, so Docusaurus treats it as a configuration mistake and aborts. The check is intentionally fail-fast (commented 'not because all subitems are drafts') so authors notice empty categories immediately rather than shipping dead nav nodes.
Source
Thrown at packages/docusaurus-plugin-content-docs/src/sidebars/postProcessor.ts:54
const permalink = normalizeUrl([params.version.path, slug]);
return {
...category.link,
slug,
permalink,
};
}
return category.link;
}
function postProcessSidebarItem(
item: ProcessedSidebarItem,
params: SidebarPostProcessorParams,
): SidebarItem | null {
if (item.type === 'category') {
// Fail-fast if there's actually no subitems, no because all subitems are
// drafts. This is likely a configuration mistake.
if (item.items.length === 0 && !item.link) {
throw new Error(
`Sidebar category ${item.label} has neither any subitem nor a link. This makes this item not able to link to anything.`,
);
}
const category = {
...item,
collapsed: item.collapsed ?? params.sidebarOptions.sidebarCollapsed,
collapsible: item.collapsible ?? params.sidebarOptions.sidebarCollapsible,
link: normalizeCategoryLink(item, params),
items: item.items
.map((subItem) => postProcessSidebarItem(subItem, params))
.filter((v): v is SidebarItem => Boolean(v)),
};
// If the current category doesn't have subitems, we render a normal link
// instead.
if (category.items.length === 0) {
// Doesn't make sense to render an empty generated index page, so we
// filter the entire category out as well.View on GitHub (pinned to 3f483e80e3)
Solutions
- Give the category a link so it resolves to a page: {type:'category', label:'X', link:{type:'doc', id:'x/index'}, items:[]}.
- Add at least one non-draft child doc to the category's items (or to the backing directory for autogenerated categories).
- Remove the empty category from the sidebar entirely if it is no longer needed.
- If children are drafts you actually want published, set draft:false on at least one of them.
Example fix
// before: category with no children and no link
const sidebars = {
guide: [{type: 'category', label: 'Empty', items: []}],
};
// after: give it a generated-index link
const sidebars = {
guide: [{
type: 'category',
label: 'Empty',
link: {type: 'generated-index'},
items: [],
}],
}; Defensive patterns
Strategy: validation
Validate before calling
// Walk the sidebar tree and flag categories that would trigger the error.
function findEmptyLinklessCategories(items, acc = []) {
for (const item of items) {
if (item.type === 'category') {
if ((!item.items || item.items.length === 0) && !item.link) {
acc.push(item.label);
}
if (item.items) findEmptyLinklessCategories(item.items, acc);
}
}
return acc;
}
const bad = findEmptyLinklessCategories(sidebars.tutorial);
if (bad.length) throw new Error('Empty linkless categories: ' + bad.join(', ')); Type guard
function categoryHasTarget(cat) {
return (Array.isArray(cat.items) && cat.items.length > 0) || Boolean(cat.link);
} Prevention
- Never declare a category without at least one child or a link.
- When converting docs to drafts, check parent categories still resolve.
- For autogenerated folders, ensure each _category_ folder holds at least one published doc.
When it happens
Trigger: Declaring a category in sidebars.js with an empty items array and no link property; a category whose only children are all draft docs (filtered out before this check runs); an autogenerated category whose directory contains only draft or unlisted files; removing the last child of a category during refactoring without giving the category a link.
Common situations: Adding a placeholder category intending to fill it later; setting draft: true on every doc inside a folder that backs a category; deleting the last doc in a category; converting all child docs to ref items that get filtered out; migration where a category lost its children but kept its label.
Related errors
- Can't find any doc with ID ${docId}. Available doc IDs: - ${
- Invalid sidebar items collection code=${JSON.stringify(sideb
- Invalid sidebar file at "${toMessageRelativeFilePath(sidebar
- Multiple docs sidebar items produce the same translation key
- The path to the sidebar file does not exist at "${path.relat
AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12).
Data as JSON: /api/errors/f8c30a9295bac186.
Report an issue: GitHub.