CherryHQ/cherry-studio · error · Error

Invalid MCP package upload: expected a .${packageFormat} fil

Error message

Invalid MCP package upload: expected a .${packageFormat} file

What it means

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.

Source

Thrown at src/main/ai/mcp/McpPackageService.ts:300

  if (typeof fileName !== 'string') {
    throw new Error('Invalid MCP package upload: file name must be a string')
  }

  const trimmedFileName = fileName.trim()
  if (!trimmedFileName) {
    throw new Error('Invalid MCP package upload: file name cannot be empty')
  }
  if (trimmedFileName !== fileName) {
    throw new Error('Invalid MCP package upload: file name cannot contain leading or trailing whitespace')
  }
  if (trimmedFileName.includes('\0') || /[/\\]/.test(trimmedFileName)) {
    throw new Error('Invalid MCP package upload: file name cannot contain path separators')
  }
  if (!/^[A-Za-z0-9._ ()@+-]+$/.test(trimmedFileName)) {
    throw new Error('Invalid MCP package upload: file name contains unsupported characters')
  }
  if (path.extname(trimmedFileName).toLowerCase() !== `.${packageFormat}`) {
    throw new Error(`Invalid MCP package upload: expected a .${packageFormat} file`)
  }

  let buffer: Buffer
  if (fileBuffer instanceof ArrayBuffer) {
    buffer = Buffer.from(fileBuffer)
  } else if (ArrayBuffer.isView(fileBuffer)) {
    buffer = Buffer.from(fileBuffer.buffer, fileBuffer.byteOffset, fileBuffer.byteLength)
  } else {
    throw new Error('Invalid MCP package upload: file buffer must be an ArrayBuffer')
  }

  if (buffer.byteLength === 0) {
    throw new Error('Invalid MCP package upload: file buffer cannot be empty')
  }
  if (buffer.byteLength > MCP_PACKAGE_UPLOAD_MAX_BYTES) {
    throw new Error('Invalid MCP package upload: file exceeds the 100 MiB size limit')
  }

View on GitHub (pinned to 726446b54c)

Solutions

  1. Confirm the actual extension of the selected file and route to the matching method (uploadDxt for .dxt, uploadMcpb for .mcpb).
  2. 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).
  3. In the renderer, derive the format from file.name extension and call the right IPC method.

Example fix

// renderer - before
await ipcApi.request('mcp.uploadDxt', { fileBuffer, fileName: 'pkg.mcpb' })
// after
const ext = fileName.split('.').pop()?.toLowerCase()
const route = ext === 'mcpb' ? 'mcp.uploadMcpb' : 'mcp.uploadDxt'
await ipcApi.request(route, { fileBuffer, fileName })
Defensive patterns

Strategy: validation

Validate before calling

import * as path from 'path'
function extensionMatchesFormat(fileName: string, format: 'dxt' | 'mcpb'): boolean {
  return path.extname(fileName).toLowerCase() === '.' + format
}

Type guard

function hasFormatExtension(fileName: string, format: 'dxt' | 'mcpb'): boolean {
  return path.extname(fileName).toLowerCase() === '.' + format
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/c17f07811c3d61a9. Report an issue: GitHub.