{"record":{"id":"c23d9e349eb8fe85","repo":"mihomo-party-org/clash-party","slug":"failed-to-copy-critical-file-file-result-rea","errorCode":null,"errorMessage":"Failed to copy critical file ${file}: ${result.reason}","messagePattern":"Failed to copy critical file (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/main/utils/init.ts","lineNumber":278,"sourceCode":"    {\n      name: 'sub-store-frontend',\n      targetDirs: [mihomoWorkDir()]\n    }\n  ]\n\n  const criticalFiles = ['country.mmdb', 'geoip.dat', 'geosite.dat']\n\n  const results = await Promise.allSettled(\n    files.map(({ name, targetDirs }) => copyFile(name, targetDirs))\n  )\n\n  for (let i = 0; i < results.length; i++) {\n    const result = results[i]\n    if (result.status === 'rejected') {\n      const file = files[i].name\n      await initLogger.error(`Failed to copy ${file}`, result.reason)\n      if (criticalFiles.includes(file)) {\n        throw new Error(`Failed to copy critical file ${file}: ${result.reason}`)\n      }\n    }\n  }\n}\n\nasync function cleanup(): Promise<void> {\n  const [dataFiles, logFiles] = await Promise.all([readdir(dataDir()), readdir(logDir())])\n\n  // 清理更新缓存\n  const cacheExtensions = ['.exe', '.pkg', '.7z']\n  const cacheCleanup = dataFiles\n    .filter((file) => cacheExtensions.some((ext) => file.endsWith(ext)))\n    .map((file) => rm(path.join(dataDir(), file)).catch(() => {}))\n\n  // 清理过期日志\n  const { maxLogDays = 7 } = await getAppConfig()\n  const maxAge = maxLogDays * 24 * 60 * 60 * 1000\n  const datePattern = /\\d{4}-\\d{2}-\\d{2}/","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/mihomo-party-org/clash-party/blob/911e090537acdf7c50bee1c3aebecc2ef119a8b5/src/main/utils/init.ts#L260-L296","documentation":"initFiles copies a set of runtime files in parallel (Promise.allSettled) and inspects each result. If a copy was rejected AND that file is listed in criticalFiles, it throws 'Failed to copy critical file <name>: <reason>' after logging via initLogger. Non-critical file failures are logged but tolerated; critical failures abort startup because the app cannot run without them.","triggerScenarios":"ensureRuntimeFiles -> initFiles where a copy promise rejects for a file in criticalFiles: source template missing from the packaged app (asar packaging excluded it), destination directory not writable (permission/EACCES), disk full, or the destination file locked by another running instance/antivirus.","commonSituations":"macOS translocation or missing extraResources entry so the bundled default config is absent; first run under a user account without write access to the config directory; a previous crashed instance holding a lock; read-only app install on Windows Program Files; disk quota exceeded.","solutions":["Read the <reason> suffix: EACCES/EPERM → fix directory permissions; ENOSPC → free disk space; ENOENT → the packaged source file is missing.","If ENOENT, check packaging config (electron-builder extraResources/files) so the template file ships inside the app bundle.","Ensure only one instance of the app runs (single-instance lock) and exclude the config dir from antivirus locking.","Verify the destination config directory exists and is writable by the current user before initFiles runs.","Check initLogger output for the 'Failed to copy <file>' entry to see the full underlying error."],"exampleFix":"// before\nawait fs.copyFile(src, dest)\n// after: ensure destination directory exists first\nawait fs.mkdir(dirname(dest), { recursive: true })\nawait fs.copyFile(src, dest)","handlingStrategy":"try-catch","validationCode":"import { accessSync, constants, existsSync } from 'fs'\n// preflight every critical file: source present, destination dir writable\nfor (const f of criticalFiles) {\n  if (!existsSync(sourcePath(f))) throw new Error(`Bundled source missing for ${f}; check packaging config`)\n  accessSync(dirname(destPath(f)), constants.W_OK)\n}","typeGuard":null,"tryCatchPattern":"try {\n  await ensureRuntimeFiles()\n} catch (e) {\n  const m = String(e).match(/Failed to copy critical file (.+?): (.+)/)\n  if (m) {\n    const [, file, reason] = m\n    if (/EACCES|EPERM/.test(reason)) promptFixPermissions(dirname(destPath(file)))\n    else if (/ENOENT/.test(reason)) repairPackagedFiles()\n    else if (/ENOSPC/.test(reason)) promptFreeDiskSpace()\n  }\n  app.quit()\n}","preventionTips":["Verify electron-builder extraResources/files includes every template the app copies at first run","Create the destination directory (mkdir recursive) before copying","Enforce a single-instance lock so concurrent startups can't lock files","Check free disk space before initialization on low-disk systems","Exclude the config directory from antivirus real-time scanning where possible"],"tags":["filesystem","initialization","file-copy","permissions","startup"],"backgroundTag":"file-copy-eacces","analyzedSha":"911e090537acdf7c50bee1c3aebecc2ef119a8b5","analyzedAt":"2026-08-30T13:00:49.174Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}