{"record":{"id":"017fdd0e3991dbf9","repo":"moeru-ai/airi","slug":"extension-manifest-is-not-valid-json-error-message","errorCode":null,"errorMessage":"Extension manifest is not valid JSON: ${error.message}","messagePattern":"Extension manifest is not valid JSON: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/main/services/airi/plugins/host/directory-import.ts","lineNumber":224,"sourceCode":"  if (!manifestFile) {\n    throw new Error(`Extension manifest does not exist: ${manifestPath}`)\n  }\n  if (manifestFile.size > extensionPackageLimits.manifestBytes) {\n    throw new Error('Extension manifest exceeds the 1 MiB size limit.')\n  }\n\n  // The manifest remains the only retained byte snapshot because the preview\n  // and fingerprint must describe the same manifest contents. The stable file\n  // handle limits the allocation even if another process grows the path.\n  const manifestContents = await readManifestSnapshot(manifestFile.path, manifestFile.size)\n\n  let rawManifest: unknown\n  try {\n    rawManifest = JSON.parse(manifestContents.toString('utf8')) as unknown\n  }\n  catch (error) {\n    if (error instanceof SyntaxError) {\n      throw new Error(`Extension manifest is not valid JSON: ${error.message}`)\n    }\n    throw error\n  }\n\n  const parsedManifest = parseExtensionManifest(rawManifest)\n  if (!parsedManifest.success) {\n    throw new Error(`Extension manifest is invalid: ${formatManifestDiagnostics(parsedManifest.diagnostics)}`)\n  }\n\n  for (const entrypoint of Object.values(parsedManifest.manifest.entrypoints)) {\n    if (!entrypoint) {\n      continue\n    }\n    if (isAbsolute(entrypoint)) {\n      throw new Error(`Imported Extension entrypoints must be relative paths: ${entrypoint}`)\n    }\n    const resolvedEntrypoint = resolve(sourceRealPath, entrypoint)\n    if (!isContainedPath(sourceRealPath, resolvedEntrypoint)) {","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/moeru-ai/airi/blob/438a067dde47aa0bdb46c2323d1fe293dc805218/apps/stage-tamagotchi/src/main/services/airi/plugins/host/directory-import.ts#L206-L242","documentation":"The manifest snapshot bytes are parsed with JSON.parse; if parsing raises a SyntaxError it is rethrown with a clearer message. This means the manifest file exists and was read successfully but its bytes are not syntactically valid JSON.","triggerScenarios":"Calling inspectExtensionDirectory when manifest.json contains malformed JSON — trailing commas, unquoted keys, comments, BOM-related issues, truncated writes, or wrong encoding (UTF-16).","commonSituations":"A hand-edited manifest with a missing comma or quote; a JSON file with // comments (JSON5-style) that strict JSON.parse rejects; an interrupted save left a truncated file; the file was saved with a UTF-8 BOM or non-UTF8 encoding.","solutions":["Validate manifest.json with a JSON linter/parser (`node -e \"JSON.parse(require('fs').readFileSync('manifest.json'))\"` or jq) and fix the syntax error reported in the message.","Remove comments and trailing commas — the parser is strict JSON, not JSON5/JSONC.","Re-save the file as UTF-8 without BOM; ensure it is not UTF-16.","Restore the manifest from version control or re-extract the package if the file is truncated."],"exampleFix":"// before: manifest.json\n{ \"name\": \"x\", \"entrypoints\": {...}, } // trailing comma -> throws\n// after\n{ \"name\": \"x\", \"entrypoints\": {...} }","handlingStrategy":"validation","validationCode":"import { readFile } from 'node:fs/promises'\nfunction assertValidManifestJson(path: string) {\n  const text = (await readFile(path, 'utf8')).replace(/^\\uFEFF/, '')\n  JSON.parse(text) // throws SyntaxError with position if invalid\n}","typeGuard":"function isParseableJson(text: string): boolean {\n  try { JSON.parse(text.replace(/^\\uFEFF/, '')); return true }\n  catch { return false }\n}","tryCatchPattern":"try {\n  await inspected(folder)\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith('Extension manifest is not valid JSON')) {\n    showUserError(`Fix manifest.json syntax: ${error.message}`)\n    return\n  }\n  throw error\n}","preventionTips":["Validate manifest.json with jq or a JSON linter in your build pipeline.","Author manifests in a JSON-aware editor; never append comments or trailing commas.","Save as UTF-8 without BOM; strip BOMs before shipping.","Don't hand-edit JSON in editors without syntax checking."],"tags":["json","manifest","extensions","parsing"],"backgroundTag":"json-parse-error","analyzedSha":"438a067dde47aa0bdb46c2323d1fe293dc805218","analyzedAt":"2026-09-17T01:14:42.644Z","contentChangedAt":"2026-09-17T01:14:42.644Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}