ramensoftware/windhawk · error

Failed to parse mod metadata

Error message

Failed to parse mod metadata

What it means

extractMetadataOrThrow wraps core.parseModSource for handlers that need metadata or nothing: if the parsed result has no metadata it throws, preferring the core's own metadata error string and falling back to this generic message. It reproduces the throw-on-parse-failure behavior modSource.extractMetadata previously had.

Solutions

  1. Open the mod source and confirm the // ==WindhawkMod== ... // ==/WindhawkMod== header block exists and is well-formed.
  2. Fix the syntax/metadata errors listed in parsed.errors (the thrown message may already carry the core's specific error).
  3. Ensure the correct language argument is passed to parseModSource for the file.
  4. Validate the metadata block with a known-good mod as a template before re-running the operation.

Example fix

// before (broken mod source)
// ==WindhawkMod==
//@id           my.mod
// ==/WindhawkMod==   <- missing name, parse fails
// after
// ==WindhawkMod==
//@id           my.mod
//@name         My Mod
// ==/WindhawkMod==
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check before calling handlers that need metadata
const src = fs.readFileSync(modPath, 'utf8');
if (!src.includes('==WindhawkMod==') || !src.includes('==/WindhawkMod==')) {
  throw new Error(`${modPath}: missing ==WindhawkMod== metadata block`);
}

Type guard

function hasMetadata(parsed: { metadata?: ModMetadata | null }): parsed is { metadata: ModMetadata } {
  return parsed.metadata != null;
}

Try / catch

try {
  const meta = await extractMetadataOrThrow(core, modSource, 'text/x-c++src');
} catch (e) {
  if (e.message.includes('Failed to parse mod metadata') || e.message.includes('metadata')) {
    openModAndHighlightMetadataBlock();
  } else { throw e; }
}

Prevention

When it happens

Trigger: Any handler (e.g. build, metadata display, mod install prep) calls extractMetadataOrThrow with mod source that clang-format/parse cannot yield metadata from: a syntax error in the .windhawk mod source, missing // ==WindhawkMod== header block, malformed metadata fields, or wrong language passed to parseModSource.

Common situations: A mod file is missing the ==WindhawkMod== metadata block or has a typo in it (e.g. ==WindhawkMod== with wrong casing/spacing); a partially written mod being edited mid-save; a file that is C++ source but submitted with the wrong language id.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

}

// Surface each failed parseModSource section as its own error notification,
// leaving the other sections' parsing unaffected.
function reportModSourceParseErrors(parsed: ParsedModSource) {
	for (const error of [parsed.errors.metadata, parsed.errors.readme, parsed.errors.initialSettings]) {
		if (error !== undefined) {
			reportException(new Error(error));
		}
	}
}

// Metadata-or-throw convenience over parseModSource for the handlers that
// previously called modSource.extractMetadata directly (which threw on any
// parse failure).
async function extractMetadataOrThrow(core: WindhawkCore, modSource: string, language: string): Promise<ModMetadata> {
	const parsed = await core.parseModSource(modSource, language);
	if (!parsed.metadata) {
		throw new Error(parsed.errors.metadata ?? 'Failed to parse mod metadata');
	}
	return parsed.metadata;
}

// Surface the clang warnings a successful local compile still produced. Append
// them to the compiler-output channel and return whether anything was written,
// so the caller can decide whether to reveal the channel (without stealing
// focus). A clean compile or a precompiled download carries no warnings, so this
// is a no-op there.
function appendCompilerWarnings(warnings: string | undefined): boolean {
	if (!warnings) {
		return false;
	}
	windhawkCompilerOutput?.append(warnings + '\n');
	return true;
}

function reportCompilerException(e: any, treatCompilationErrorAsException = false) {

View on GitHub (pinned to 61d99ed8e1)