CherryHQ/cherry-studio · error · Error
${packageLabel} file not found
Error message
${packageLabel} file not found What it means
Thrown near the top of uploadPackage's try block when fs.existsSync(filePath) returns false. uploadPackage is the shared extract/install path invoked after uploadFromBuffer stages the buffer to a temp file; it is also the natural place a direct file-path install would start. The check is a precondition guard before StreamZip opens the file.
Source
Thrown at src/main/ai/mcp/McpPackageService.ts:512
await fs.promises.writeFile(tempPath, fileData)
return await this.uploadPackage(tempPath, packageFormat)
} catch (error) {
logger.error(`${packageLabel} upload error:`, error as Error)
return {
success: false,
error: error instanceof Error ? error.message : `Failed to upload ${packageLabel} file`
}
}
}
private async uploadPackage(filePath: string, packageFormat: McpPackageFormat): Promise<McpPackageUploadResult> {
const packageLabel = packageFormat === 'mcpb' ? 'MCPB' : 'DXT'
const tempExtractDir = path.join(this.tempDir, `${packageFormat}_${uuidv4()}`)
try {
// Validate file exists
if (!fs.existsSync(filePath)) {
throw new Error(`${packageLabel} file not found`)
}
// Extract the package file (which is a ZIP archive) to a temporary directory
logger.debug(`Extracting ${packageLabel} file: ${filePath}`)
const zip = new StreamZip.async({ file: filePath })
try {
// Reject any zip-slip entry before writing anything to disk.
assertZipEntriesWithin(Object.keys(await zip.entries()), tempExtractDir)
await zip.extract(null, tempExtractDir)
} finally {
await zip.close()
}
// Read and validate the manifest.json
const manifestPath = path.join(tempExtractDir, 'manifest.json')
if (!fs.existsSync(manifestPath)) {
throw new Error(`manifest.json not found in ${packageLabel} file`)View on GitHub (pinned to 726446b54c)
Solutions
- Avoid calling service.cleanup() while uploads are in flight; ensure the lifecycle stops the service only after pending uploads complete.
- If the temp dir is being cleared by an external process, move the temp dir (application.getPath('feature.dxt.uploads.temp')) to a location not scanned by AV/sync.
- Retry the upload; if it fails again, inspect main-process logs for concurrent cleanup or shutdown around the same timestamp.
Defensive patterns
Strategy: try-catch
Validate before calling
import * as fs from 'fs'
function fileExistsAtPath(filePath: string): boolean {
return fs.existsSync(filePath)
} Try / catch
// uploadFromBuffer/uploadPackage already wraps this in try/catch and returns { success: false, error }.
// Callers of uploadDxt/uploadMcpb should check the result shape, not await a throw.
const result = await mcpPackageService.uploadDxt(buf, name)
if (!result.success) {
notifyUser(result.error ?? 'Upload failed')
} Prevention
- Do not call McpPackageService.cleanup() concurrently with uploads; gate cleanup on pending upload completion.
- If an external process (AV, sync) quarantines files in the temp dir, relocate the temp dir to a non-scanned path.
- When calling uploadPackage directly in tests, assert fs.existsSync(filePath) before invoking.
When it happens
Trigger: The temp file written by uploadFromBuffer was removed before uploadPackage ran (race with another cleanup, antivirus quarantine, the service cleanup() running concurrently); or uploadPackage was called directly with a path that does not exist.
Common situations: Concurrent calls to McpPackageService.cleanup() (e.g. on app shutdown) deleted the temp dir mid-upload; an antivirus or sync tool quarantined the freshly written temp file; a developer invoked uploadPackage in a test with a non-existent path.
Related errors
- File not found: ${displayPath}
- File exceeds the ${MAX_FILE_SIZE_BYTES} byte limit (${data.l
- Invalid MCP package upload: file name must be a string
- Invalid MCP package upload: file name cannot be empty
- Invalid MCP package upload: file name cannot contain leading
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/68ba0957874d829e.
Report an issue: GitHub.