mermaid-js/mermaid · error
Invalid icon loader. Must have either "icons" or "loader" pr
Error message
Invalid icon loader. Must have either "icons" or "loader" property.
What it means
Thrown by registerIconPacks after the name check passes but the loader object has neither a `loader` function (async pack) nor an `icons` object (static pack). The registry stores one or the other keyed by name, so the object must carry exactly one of these properties. The preceding log.error('Invalid icon loader:', iconLoader) prints the offending object.
Source
Thrown at packages/mermaid/src/rendering-util/icons.ts:43
const iconsStore = new Map<string, IconifyJSON>();
const loaderStore = new Map<string, AsyncIconLoader['loader']>();
export const registerIconPacks = (iconLoaders: IconLoader[]) => {
for (const iconLoader of iconLoaders) {
if (!iconLoader.name) {
throw new Error(
'Invalid icon loader. Must have a "name" property with non-empty string value.'
);
}
log.debug('Registering icon pack:', iconLoader.name);
if ('loader' in iconLoader) {
loaderStore.set(iconLoader.name, iconLoader.loader);
} else if ('icons' in iconLoader) {
iconsStore.set(iconLoader.name, iconLoader.icons);
} else {
log.error('Invalid icon loader:', iconLoader);
throw new Error('Invalid icon loader. Must have either "icons" or "loader" property.');
}
}
};
const getRegisteredIconData = async (iconName: string, fallbackPrefix?: string) => {
const data = stringToIcon(iconName, true, fallbackPrefix !== undefined);
if (!data) {
throw new Error(`Invalid icon name: ${iconName}`);
}
const prefix = data.prefix || fallbackPrefix;
if (!prefix) {
throw new Error(`Icon name must contain a prefix: ${iconName}`);
}
let icons = iconsStore.get(prefix);
if (!icons) {
const loader = loaderStore.get(prefix);
if (!loader) {
throw new Error(`Icon set not found: ${data.prefix}`);View on GitHub (pinned to d93e9c88c0)
Solutions
- Provide exactly one of `loader: () => Promise<IconifyJSON>` (async/lazy) or `icons: IconifyJSON` (static/eager) on each loader object.
- For lazy loading use loader: () => import('@iconify-json/logos').then((m) => m.icons); for eager use import { icons } from '@iconify-json/logos' and pass { name, icons }.
- Check the console immediately before this error — log.error prints the full invalid object so you can see which key is missing/misspelled.
- Validate against the IconLoader union type so TypeScript flags objects missing the required discriminating property.
Example fix
// before
mermaid.registerIconPacks([{ name: 'logos' }]);
// after
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((m) => m.icons),
},
]); Defensive patterns
Strategy: type-guard
Validate before calling
function hasIconsOrLoader(x: any): boolean {
return (typeof x.loader === 'function') || (x.icons && typeof x.icons === 'object');
}
for (const l of loaders) if (!hasIconsOrLoader(l)) throw new Error(`loader ${l.name} needs icons or loader`); Type guard
function isAsyncIconLoader(x: any): x is { name: string; loader: () => Promise<any> } {
return typeof x.name === 'string' && typeof x.loader === 'function';
}
function isSyncIconLoader(x: any): x is { name: string; icons: object } {
return typeof x.name === 'string' && x.icons && typeof x.icons === 'object';
} Try / catch
try { mermaid.registerIconPacks(loaders); } catch (e) { if (/icons or loader/.test(String(e))) console.error('each loader needs icons or loader:', loaders); throw e; } Prevention
- Always copy a working example's full object shape including name and loader/icons.
- Use the IconLoader union type to get compile-time checks.
- Inspect the log.error output that precedes this throw to see the exact bad object.
When it happens
Trigger: Passing { name: 'logos' } alone, { name: 'logos', src: '...' } (wrong key like `src`), or { name: 'logos', icon: {...} } (singular `icon` instead of `icons`). Any name-bearing object missing both `loader` and `icons` keys hits the final else branch.
Common situations: Mistyping the property (`Icon`/`Loader` capitalized, `iconData`, `data`), or upgrading from an older API where the shape differed. Also from partial spreads: { name: 'x', ...rest } where rest happened to omit both keys.
Related errors
- Invalid icon loader. Must have a "name" property with non-em
- Icon name must contain a prefix: ${iconName}
- Invalid icon name: ${iconName}
- Icon set not found: ${data.prefix}
- Icon not found: ${iconName}
AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12).
Data as JSON: /api/errors/ad79dee5b406530c.
Report an issue: GitHub.