ramensoftware/windhawk · error

Mod id specified in the source code doesn't match

Error message

Mod id specified in the source code doesn't match

What it means

During install, extractMetadataOrThrow derives the id from the mod source and it is compared against the modId supplied by the panel message. If the source's id differs from the target storageId, the extension refuses to install to avoid writing a mod under the wrong identity.

Solutions

  1. Make the id inside the mod source's metadata match the modId passed to the install call
  2. Update the caller so modId is derived from the source metadata instead of hardcoded
  3. If renaming intentionally, create a fresh install with the new id

Example fix

// before
id=old.mod.id  // installed as storageId 'new.mod.id'
// after
id=new.mod.id  // matches storageId
Defensive patterns

Strategy: validation

Validate before calling

const meta = parseModMetadata(modSource);
if (meta?.id && meta.id !== data.modId) {
  console.warn(`id mismatch: source=${meta.id} target=${data.modId}`);
}

Type guard

const idsMatch = (sourceId: string, storageId: string): boolean => sourceId === storageId;

Try / catch

try { await panel.installMod(data); } catch (e) { if (e.message.includes("doesn't match")) promptIdCorrection(e); else throw e; }

Prevention

When it happens

Trigger: WindhawkPanel install flow where metadata.id !== data.modId — e.g. editing an existing mod's source to a new id but installing into the old slot, or mismatched casing.

Common situations: Duplicating a mod and changing its id but reusing a stale UI session; uploading a different mod's file under another mod's entry.

Related errors


AI-assisted analysis of ramensoftware/windhawk@61d99ed8e1 (2026-09-12). Data as JSON: /api/errors/6b0f378e987bf3c4. Report an issue: GitHub.

Appendix: source

Thrown at src/windhawk-vscode/src/extension.ts:834

		},
		installMod: async message => {
			const data: InstallModData = message.data;

			let installedModDetails: InstallModReplyData['installedModDetails'] = null;
			let readBackError: WireError | undefined;

			try {
				windhawkCompilerOutput?.clear();
				windhawkCompilerOutput?.hide();

				const modId = data.modId;
				const modSource = data.modSource;

				const metadata = await extractMetadataOrThrow(this._utils.core, modSource, this._language);
				if (!metadata.id) {
					throw new Error('Mod id must be specified in the source code');
				} else if (metadata.id !== modId) {
					throw new Error('Mod id specified in the source code doesn\'t match');
				}

				const op = this._utils.core.installMod({
					storageId: modId,
					source: modSource,
					metadata,
					disabled: data.disabled,
					loggingEnabled: data.loggingEnabled,
					compileLocally: this._alwaysCompileModsLocally,
					trackInProfile: true,
				});

				// Track the operation for the duration of the install so
				// cancelInstallMod can find it, and drop it however it settles -
				// a completion, a failure, or the cancel itself.
				this._currentInstallOps.set(modId, op);
				let result: InstallModResult;
				try {

View on GitHub (pinned to 61d99ed8e1)