{"record":{"id":"6584f208467b33e6","repo":"CherryHQ/cherry-studio","slug":"invalid-mcp-package-upload-file-name-must-be-a-st","errorCode":null,"errorMessage":"Invalid MCP package upload: file name must be a string","messagePattern":"Invalid MCP package upload: file name must be a string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/McpPackageService.ts","lineNumber":283,"sourceCode":"\n    const substituted = performVariableSubstitution(value, extractDir, userConfig)\n    if (substituted.includes('\\0')) {\n      throw new Error(`Invalid MCP package env: null byte detected in value of environment variable \"${key}\"`)\n    }\n\n    resolvedEnv[key] = substituted\n  }\n\n  return resolvedEnv\n}\n\nexport function validatePackageUploadPayload(\n  fileBuffer: ArrayBuffer | NodeJS.ArrayBufferView,\n  fileName: string,\n  packageFormat: McpPackageFormat\n): Buffer {\n  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  }","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/McpPackageService.ts#L265-L301","documentation":"Thrown by validatePackageUploadPayload when the fileName parameter is not a string. This is a TypeScript runtime guard for the upload entry point (uploadDxt/uploadMcpb → uploadFromBuffer → validatePackageUploadPayload); although the type signature requires string, IPC input from the renderer is untyped at the boundary and a non-string (number, object, undefined) can arrive.","triggerScenarios":"The renderer IPC call that sends the ArrayBuffer also sent a fileName that is undefined, null, a number, or an object. For example a form that forgot to set the filename field, or a test that passed a File object directly instead of file.name.","commonSituations":"Frontend code constructs the IPC payload incorrectly (e.g. passes the File/Blob object instead of its .name property); a refactor changed the IPC schema and the renderer was not updated; an automated test bypassed the UI with a malformed payload.","solutions":["On the renderer side, ensure the fileName passed to the upload IPC is a string, typically the File.name property of the selected file.","If you control the IPC schema, narrow the type at the boundary (zod/schema validation) so non-strings are rejected with a clearer message before reaching the service.","Reproduce the call and log typeof fileName at the IPC handler to confirm what the renderer actually sent."],"exampleFix":"// renderer - before\nawait ipcApi.request('mcp.uploadDxt', { fileBuffer: await file.arrayBuffer(), fileName: file })\n// after\nawait ipcApi.request('mcp.uploadDxt', { fileBuffer: await file.arrayBuffer(), fileName: file.name })","handlingStrategy":"type-guard","validationCode":"function isStringFileName(fileName: unknown): boolean {\n  return typeof fileName === 'string'\n}","typeGuard":"function isUploadFileName(fileName: unknown): fileName is string {\n  return typeof fileName === 'string'\n}","tryCatchPattern":"// At the IPC handler boundary, narrow before delegating.\nfunction handleUpload(payload: unknown) {\n  if (typeof payload !== 'object' || payload === null) return badRequest()\n  const { fileName, fileBuffer } = payload as { fileName?: unknown; fileBuffer?: unknown }\n  if (typeof fileName !== 'string') return badRequest('fileName must be a string')\n  // ...then call uploadDxt/uploadMcpb\n}","preventionTips":["Validate the IPC payload shape at the handler boundary with a schema (zod) so non-string fileName never reaches the service.","On the renderer, always derive fileName from File.name and type the upload call so a non-string is a compile error.","Add a renderer unit test asserting the IPC is only dispatched with a string fileName."],"tags":["mcp","upload","validation","ipc","typescript"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}