{"record":{"id":"c17f07811c3d61a9","repo":"CherryHQ/cherry-studio","slug":"invalid-mcp-package-upload-expected-a-packagef","errorCode":null,"errorMessage":"Invalid MCP package upload: expected a .${packageFormat} file","messagePattern":"Invalid MCP package upload: expected a \\.(.+?) file","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/McpPackageService.ts","lineNumber":300,"sourceCode":"  if (typeof fileName !== 'string') {\n    throw new Error('Invalid MCP package upload: file name must be a string')\n  }\n\n  const trimmedFileName = fileName.trim()\n  if (!trimmedFileName) {\n    throw new Error('Invalid MCP package upload: file name cannot be empty')\n  }\n  if (trimmedFileName !== fileName) {\n    throw new Error('Invalid MCP package upload: file name cannot contain leading or trailing whitespace')\n  }\n  if (trimmedFileName.includes('\\0') || /[/\\\\]/.test(trimmedFileName)) {\n    throw new Error('Invalid MCP package upload: file name cannot contain path separators')\n  }\n  if (!/^[A-Za-z0-9._ ()@+-]+$/.test(trimmedFileName)) {\n    throw new Error('Invalid MCP package upload: file name contains unsupported characters')\n  }\n  if (path.extname(trimmedFileName).toLowerCase() !== `.${packageFormat}`) {\n    throw new Error(`Invalid MCP package upload: expected a .${packageFormat} file`)\n  }\n\n  let buffer: Buffer\n  if (fileBuffer instanceof ArrayBuffer) {\n    buffer = Buffer.from(fileBuffer)\n  } else if (ArrayBuffer.isView(fileBuffer)) {\n    buffer = Buffer.from(fileBuffer.buffer, fileBuffer.byteOffset, fileBuffer.byteLength)\n  } else {\n    throw new Error('Invalid MCP package upload: file buffer must be an ArrayBuffer')\n  }\n\n  if (buffer.byteLength === 0) {\n    throw new Error('Invalid MCP package upload: file buffer cannot be empty')\n  }\n  if (buffer.byteLength > MCP_PACKAGE_UPLOAD_MAX_BYTES) {\n    throw new Error('Invalid MCP package upload: file exceeds the 100 MiB size limit')\n  }\n","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/McpPackageService.ts#L282-L318","documentation":"Thrown by validatePackageUploadPayload when the filename's extension does not match the expected package format. The check is path.extname(trimmedFileName).toLowerCase() === '.' + packageFormat, so for uploadDxt the file must end in .dxt and for uploadMcpb it must end in .mcpb. The format is fixed per entry point; you cannot upload a .mcpb through uploadDxt or vice-versa.","triggerScenarios":"Renderer called uploadDxt with a file named \"pkg.mcpb\" (or .zip, or no extension), or called uploadMcpb with a .dxt file. Also triggered if the renderer's UI lets the user pick the format but the wrong upload method was invoked.","commonSituations":"Frontend dispatch logic picked the wrong method based on the detected extension; the user renamed a .dxt to .mcpb or vice-versa; the upload method was hardcoded during development and not switched when the test fixture format changed.","solutions":["Confirm the actual extension of the selected file and route to the matching method (uploadDxt for .dxt, uploadMcpb for .mcpb).","If the file is genuinely the wrong format, obtain the correct file (a .dxt cannot be processed as .mcpb even if renamed, because the manifest validation also differs).","In the renderer, derive the format from file.name extension and call the right IPC method."],"exampleFix":"// renderer - before\nawait ipcApi.request('mcp.uploadDxt', { fileBuffer, fileName: 'pkg.mcpb' })\n// after\nconst ext = fileName.split('.').pop()?.toLowerCase()\nconst route = ext === 'mcpb' ? 'mcp.uploadMcpb' : 'mcp.uploadDxt'\nawait ipcApi.request(route, { fileBuffer, fileName })","handlingStrategy":"validation","validationCode":"import * as path from 'path'\nfunction extensionMatchesFormat(fileName: string, format: 'dxt' | 'mcpb'): boolean {\n  return path.extname(fileName).toLowerCase() === '.' + format\n}","typeGuard":"function hasFormatExtension(fileName: string, format: 'dxt' | 'mcpb'): boolean {\n  return path.extname(fileName).toLowerCase() === '.' + format\n}","tryCatchPattern":null,"preventionTips":["In the renderer, derive the format from file.name's extension and call the matching IPC method (uploadDxt vs uploadMcpb).","Reflect the expected extension in the file picker's accept attribute so the user is less likely to pick the wrong file type.","In tests, parameterize the upload method on the fixture's extension."],"tags":["mcp","upload","validation","ipc","file-format"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}