mihomo-party-org/clash-party · critical · Error
Failed to copy critical file ${file}: ${result.reason}
Error message
Failed to copy critical file ${file}: ${result.reason} What it means
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.
Source
Thrown at src/main/utils/init.ts:278
{
name: 'sub-store-frontend',
targetDirs: [mihomoWorkDir()]
}
]
const criticalFiles = ['country.mmdb', 'geoip.dat', 'geosite.dat']
const results = await Promise.allSettled(
files.map(({ name, targetDirs }) => copyFile(name, targetDirs))
)
for (let i = 0; i < results.length; i++) {
const result = results[i]
if (result.status === 'rejected') {
const file = files[i].name
await initLogger.error(`Failed to copy ${file}`, result.reason)
if (criticalFiles.includes(file)) {
throw new Error(`Failed to copy critical file ${file}: ${result.reason}`)
}
}
}
}
async function cleanup(): Promise<void> {
const [dataFiles, logFiles] = await Promise.all([readdir(dataDir()), readdir(logDir())])
// 清理更新缓存
const cacheExtensions = ['.exe', '.pkg', '.7z']
const cacheCleanup = dataFiles
.filter((file) => cacheExtensions.some((ext) => file.endsWith(ext)))
.map((file) => rm(path.join(dataDir(), file)).catch(() => {}))
// 清理过期日志
const { maxLogDays = 7 } = await getAppConfig()
const maxAge = maxLogDays * 24 * 60 * 60 * 1000
const datePattern = /\d{4}-\d{2}-\d{2}/View on GitHub (pinned to 911e090537)
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.
Example fix
// before
await fs.copyFile(src, dest)
// after: ensure destination directory exists first
await fs.mkdir(dirname(dest), { recursive: true })
await fs.copyFile(src, dest) Defensive patterns
Strategy: try-catch
Validate before calling
import { accessSync, constants, existsSync } from 'fs'
// preflight every critical file: source present, destination dir writable
for (const f of criticalFiles) {
if (!existsSync(sourcePath(f))) throw new Error(`Bundled source missing for ${f}; check packaging config`)
accessSync(dirname(destPath(f)), constants.W_OK)
} Try / catch
try {
await ensureRuntimeFiles()
} catch (e) {
const m = String(e).match(/Failed to copy critical file (.+?): (.+)/)
if (m) {
const [, file, reason] = m
if (/EACCES|EPERM/.test(reason)) promptFixPermissions(dirname(destPath(file)))
else if (/ENOENT/.test(reason)) repairPackagedFiles()
else if (/ENOSPC/.test(reason)) promptFreeDiskSpace()
}
app.quit()
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- TUN is enabled but insufficient permissions detected, auto-d
- Core startup is unavailable because startup safety checks di
- Invalid core path: directory traversal detected
- Unsupported plugin file type
- Plugin path is not a file
AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30).
Data as JSON: /api/errors/c23d9e349eb8fe85.
Report an issue: GitHub.