{"record":{"id":"c0602662cfdc96a7","repo":"ramensoftware/windhawk","slug":"failed-to-parse-mod-metadata","errorCode":null,"errorMessage":"Failed to parse mod metadata","messagePattern":"Failed to parse mod metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/windhawk-vscode/src/extension.ts","lineNumber":2083,"sourceCode":"}\n\n// Surface each failed parseModSource section as its own error notification,\n// leaving the other sections' parsing unaffected.\nfunction reportModSourceParseErrors(parsed: ParsedModSource) {\n\tfor (const error of [parsed.errors.metadata, parsed.errors.readme, parsed.errors.initialSettings]) {\n\t\tif (error !== undefined) {\n\t\t\treportException(new Error(error));\n\t\t}\n\t}\n}\n\n// Metadata-or-throw convenience over parseModSource for the handlers that\n// previously called modSource.extractMetadata directly (which threw on any\n// parse failure).\nasync function extractMetadataOrThrow(core: WindhawkCore, modSource: string, language: string): Promise<ModMetadata> {\n\tconst parsed = await core.parseModSource(modSource, language);\n\tif (!parsed.metadata) {\n\t\tthrow new Error(parsed.errors.metadata ?? 'Failed to parse mod metadata');\n\t}\n\treturn parsed.metadata;\n}\n\n// Surface the clang warnings a successful local compile still produced. Append\n// them to the compiler-output channel and return whether anything was written,\n// so the caller can decide whether to reveal the channel (without stealing\n// focus). A clean compile or a precompiled download carries no warnings, so this\n// is a no-op there.\nfunction appendCompilerWarnings(warnings: string | undefined): boolean {\n\tif (!warnings) {\n\t\treturn false;\n\t}\n\twindhawkCompilerOutput?.append(warnings + '\\n');\n\treturn true;\n}\n\nfunction reportCompilerException(e: any, treatCompilationErrorAsException = false) {","sourceCodeStart":2065,"sourceCodeEnd":2101,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk-vscode/src/extension.ts#L2065-L2101","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Open the mod source and confirm the // ==WindhawkMod== ... // ==/WindhawkMod== header block exists and is well-formed.","Fix the syntax/metadata errors listed in parsed.errors (the thrown message may already carry the core's specific error).","Ensure the correct language argument is passed to parseModSource for the file.","Validate the metadata block with a known-good mod as a template before re-running the operation."],"exampleFix":"// before (broken mod source)\n// ==WindhawkMod==\n//@id           my.mod\n// ==/WindhawkMod==   <- missing name, parse fails\n// after\n// ==WindhawkMod==\n//@id           my.mod\n//@name         My Mod\n// ==/WindhawkMod==","handlingStrategy":"try-catch","validationCode":"// pre-check before calling handlers that need metadata\nconst src = fs.readFileSync(modPath, 'utf8');\nif (!src.includes('==WindhawkMod==') || !src.includes('==/WindhawkMod==')) {\n  throw new Error(`${modPath}: missing ==WindhawkMod== metadata block`);\n}","typeGuard":"function hasMetadata(parsed: { metadata?: ModMetadata | null }): parsed is { metadata: ModMetadata } {\n  return parsed.metadata != null;\n}","tryCatchPattern":"try {\n  const meta = await extractMetadataOrThrow(core, modSource, 'text/x-c++src');\n} catch (e) {\n  if (e.message.includes('Failed to parse mod metadata') || e.message.includes('metadata')) {\n    openModAndHighlightMetadataBlock();\n  } else { throw e; }\n}","preventionTips":["Always include a complete, well-formed // ==WindhawkMod== header block; start from a template mod.","Lint the metadata block (ids, name, description fields) as a pre-save step in tooling.","Pass the correct language identifier to parseModSource for the file type.","Treat edits to the metadata block as high-risk and re-validate after every change."],"tags":["metadata","parse-error","validation","windhawk-mod"],"backgroundTag":"schema-validation-failed","analyzedSha":"61d99ed8e182e1af1b60109612b6763ad1b4b74e","analyzedAt":"2026-09-12T14:02:41.115Z","contentChangedAt":"2026-09-12T14:02:41.115Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}