ramensoftware/windhawk · error
MODS_LOAD_FAILED
MODS_LOAD_FAILED
Error message
${loadErrors.length} mod(s) could not be loaded. ${loadErrors.map(({ modId, error }) => error ? `${modId}: ${error}` : modId).join('; ')} What it means
Aggregated listing failure in WindhawkPanel. When one or more installed mods fail to load, each failure is surfaced individually with showErrorMessage, and the getInstalledMods reply also carries a MODS_LOAD_FAILED error summarizing the count and per-mod reasons.
Solutions
- Read the per-mod messages in the aggregated error (modId: error) and fix the specific mods listed.
- Rebuild or reinstall the failing mods; validate their .wh.cpp metadata blocks.
- If a mod is unneeded, remove its files from the mods directory so it stops failing to load.
Defensive patterns
Strategy: try-catch
Validate before calling
const reply = await webviewIPC.getInstalledMods();
if (reply.error?.code === 'MODS_LOAD_FAILED') {
const failing = reply.error.message.split('; ');
console.error('Mods failing to load:', failing);
} Type guard
const hasLoadErrors = (r: { error?: { code: string } }): boolean =>
r.error?.code === 'MODS_LOAD_FAILED'; Try / catch
try {
const listing = await loadInstalledMods();
if (listing.error?.code === 'MODS_LOAD_FAILED') {
listing.error.message.split(';').forEach(showPerModWarning);
}
} catch (e) {
console.error(e);
} Prevention
- Keep mod .wh.cpp metadata valid; run the mod through Windhawk compile before installing.
- Remove or repair mods flagged by the per-mod 'Failed to load mod <id>' toasts promptly.
- After Windhawk version upgrades, verify installed mods still load (metadata schema may change).
When it happens
Trigger: InstalledModsProvider.loadInstalledMods returns loadErrors (per-mod errors from the backend, e.g. a mod's metadata could not be parsed or the engine failed to load it), and loadErrors.length > 0 when building the installed-mods reply.
Common situations: Corrupted mod installation files; mods written by incompatible Windhawk versions; locally-built mods with invalid metadata sitting in the mods directory.
Related errors
AI-assisted analysis of ramensoftware/windhawk@61d99ed8e1 (2026-09-12).
Data as JSON: /api/errors/ffed8d4b5dfa112a.
Report an issue: GitHub.
Appendix: source
Thrown at src/windhawk-vscode/src/extension.ts:587
},
getInstalledMods: async message => {
const installedMods: GetInstalledModsReplyData['installedMods'] = {};
// Says the listing is short of the machine, so a reader that needs the
// complete set of ids does not read the map as the answer. The native
// notifications below are for the user; this is for the webview.
let listingError: WireError | undefined;
try {
const { mods, loadErrors } = await this._utils.core.listInstalledMods({
language: this._language,
checkForUpdates: this._checkForUpdates,
syncProfile: true,
});
for (const { modId, error } of loadErrors) {
vscode.window.showErrorMessage(`Failed to load mod ${modId}: ${error}`);
}
if (loadErrors.length > 0) {
listingError = {
code: 'MODS_LOAD_FAILED',
message: `${loadErrors.length} mod(s) could not be loaded. ` +
loadErrors.map(({ modId, error }) =>
error ? `${modId}: ${error}` : modId).join('; ')
};
}
// The core entry IS this reply's entry - both carry the terms of the
// update answer and neither the answer - so the whole thing rides
// through, a field the core adds included.
for (const [modId, entry] of Object.entries(mods)) {
installedMods[modId] = entry;
}
} catch (e) {
reportException(e);
listingError = {
code: 'INTERNAL',
message: e instanceof Error ? e.message : String(e)
};
}View on GitHub (pinned to 61d99ed8e1)