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

  1. Read the per-mod messages in the aggregated error (modId: error) and fix the specific mods listed.
  2. Rebuild or reinstall the failing mods; validate their .wh.cpp metadata blocks.
  3. 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

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)