{"record":{"id":"d2077ce03360cbef","repo":"CherryHQ/cherry-studio","slug":"manifest-json-not-found-in-packagelabel-file","errorCode":null,"errorMessage":"manifest.json not found in ${packageLabel} file","messagePattern":"manifest\\.json not found in (.+?) file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/McpPackageService.ts","lineNumber":530,"sourceCode":"        throw new Error(`${packageLabel} file not found`)\n      }\n\n      // Extract the package file (which is a ZIP archive) to a temporary directory\n      logger.debug(`Extracting ${packageLabel} file: ${filePath}`)\n\n      const zip = new StreamZip.async({ file: filePath })\n      try {\n        // Reject any zip-slip entry before writing anything to disk.\n        assertZipEntriesWithin(Object.keys(await zip.entries()), tempExtractDir)\n        await zip.extract(null, tempExtractDir)\n      } finally {\n        await zip.close()\n      }\n\n      // Read and validate the manifest.json\n      const manifestPath = path.join(tempExtractDir, 'manifest.json')\n      if (!fs.existsSync(manifestPath)) {\n        throw new Error(`manifest.json not found in ${packageLabel} file`)\n      }\n\n      const manifestContent = fs.readFileSync(manifestPath, 'utf-8')\n      const parsedManifest: ParsedMcpPackageManifest = JSON.parse(manifestContent)\n\n      // Validate required fields in manifest\n      let manifest: McpPackageManifest\n      if (packageFormat === 'mcpb') {\n        if (!parsedManifest.manifest_version) {\n          throw new Error('Invalid manifest: missing manifest_version')\n        }\n        manifest = { ...parsedManifest, manifest_version: parsedManifest.manifest_version }\n      } else {\n        if (!parsedManifest.dxt_version) {\n          throw new Error('Invalid manifest: missing dxt_version')\n        }\n        manifest = { ...parsedManifest, dxt_version: parsedManifest.dxt_version }\n      }","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/McpPackageService.ts#L512-L548","documentation":"Thrown after ZIP extraction when fs.existsSync(path.join(tempExtractDir, 'manifest.json')) is false. The package extracted successfully (no zip-slip, no extraction error) but no manifest.json entry was present at the archive root. The manifest is the contract every mcpb/dxt package must provide; without it the service cannot determine the server command, args, or version.","triggerScenarios":"The .mcpb/.dxt archive unzips to a top-level folder (e.g. everything under pkg/) rather than to the archive root, so manifest.json lands at tempExtractDir/pkg/manifest.json; or the manifest was named differently (manifest.jsonc, package.json); or the archive was assembled without including the manifest.","commonSituations":"The zip was created with `zip -r out.mcpb mydir/` which preserves the mydir/ prefix; a build script zipped the project root's parent instead of the project root; the author renamed manifest.json or used a different schema.","solutions":["Inspect the archive layout (unzip -l pkg.mcpb) and confirm manifest.json sits at the top level, not under a subdirectory.","Re-zip from inside the package directory so entries are relative to the directory root (cd pkg && zip -r ../out.mcpb .).","Ensure the file is named exactly manifest.json (case-sensitive) and is a JSON object, not a wrapper document."],"exampleFix":"# before: zip created with parent dir\n$ unzip -l out.mcpb\n  pkg/manifest.json\n  pkg/server.js\n# after: zip from inside the dir\n$ cd pkg && zip -r ../out.mcpb .\n$ unzip -l ../out.mcpb\n  manifest.json\n  server.js","handlingStrategy":"validation","validationCode":"import * as StreamZip from 'node-stream-zip'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\nasync function archiveHasRootManifest(zipPath: string): Promise<boolean> {\n  const zip = new StreamZip.async({ file: zipPath })\n  try {\n    const entries = await zip.entries()\n    return Object.keys(entries).includes('manifest.json')\n  } finally {\n    await zip.close()\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When zipping a package, cd into the package directory first so entries are relative to the archive root (cd pkg && zip -r ../out.mcpb .).","After building, run unzip -l out.mcpb and assert manifest.json appears at the top level (no prefix).","Name the file exactly manifest.json (case-sensitive); do not use .jsonc or alternative spellings."],"tags":["mcp","manifest","upload","packaging","zip"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}