Skip to content

Commit 4333dea

Browse files
committed
fix: proper catch-all daemon startup errors
this should engage isErrored only when ipfs daemon is truly errored: - checks if pid is alive, and shows "startup error" window when process is dead - removes false-negatives caused by migration code or other "soft" errors printed to the console
1 parent cc06bcc commit 4333dea

File tree

3 files changed

+35
-15
lines changed

3 files changed

+35
-15
lines changed

assets/locales/en.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@
231231
"message": "One moment! IPFS Desktop needs to run the latest data store migrations:",
232232
"closeAndContinue": "Continue in the background"
233233
},
234-
"migrationFailedDialog": {
235-
"title": "IPFS Desktop Migration Has Failed",
236-
"message": "IPFS has encountered an error and migration could not be completed:"
234+
"startupFailedDialog": {
235+
"title": "IPFS Desktop Startup Has Failed",
236+
"message": "IPFS node has encountered an error and startup could not be completed:"
237237
}
238238
}

src/daemon/daemon.js

+30-10
Original file line numberDiff line numberDiff line change
@@ -94,24 +94,34 @@ async function startIpfsWithLogs (ipfsd) {
9494
let isMigrating, isErrored, isFinished
9595
let logs = ''
9696

97+
const isSpawnedDaemonDead = (ipfsd) => {
98+
if (typeof ipfsd.subprocess === 'undefined') throw new Error('missing ipfsd.subprocess, unable to reason about startup errors')
99+
if (ipfsd.subprocess === null) return false // not spawned yet
100+
if (ipfsd.subprocess?.failed) return true // explicit failure
101+
102+
// detect when spawned ipfsd process is gone/dead
103+
// by inspecting its pid - it should be alive
104+
const { pid } = ipfsd.subprocess
105+
try {
106+
// signal 0 throws if process is missing, noop otherwise
107+
process.kill(pid, 0)
108+
return false
109+
} catch (e) {
110+
return true
111+
}
112+
}
113+
97114
const stopListening = listenToIpfsLogs(ipfsd, data => {
98115
logs += data.toString()
99116
const line = data.toLowerCase()
100117
isMigrating = isMigrating || line.includes('migration')
101-
isErrored = isErrored || line.includes('error')
118+
isErrored = isErrored || isSpawnedDaemonDead(ipfsd)
102119
isFinished = isFinished || line.includes('daemon is ready')
103120

104-
if (!isMigrating) {
121+
if (!isMigrating && !isErrored) {
105122
return
106123
}
107124

108-
// Undo error state if retrying after HTTP failure
109-
// https://github.com/ipfs/ipfs-desktop/issues/2003
110-
if (isErrored && line.includes('fetching with ipfs') && !line.includes('error')) {
111-
isErrored = false
112-
if (migrationPrompt) migrationPrompt.loadWindow(logs, isErrored, isFinished)
113-
}
114-
115125
if (!migrationPrompt) {
116126
logger.info('[daemon] ipfs data store is migrating')
117127
migrationPrompt = showMigrationPrompt(logs, isErrored, isFinished)
@@ -134,10 +144,20 @@ async function startIpfsWithLogs (ipfsd) {
134144
} catch (e) {
135145
err = e
136146
} finally {
137-
// stop monitoring daemon output - we only care about migration phase
147+
// stop monitoring daemon output - we only care about startup phase
138148
stopListening()
149+
150+
// Show startup error using the same UI as migrations.
151+
// This is catch-all that will show stdout/stderr of ipfs daemon
152+
// that failed to start, allowing user to self-diagnose or report issue.
153+
isErrored = isErrored || isSpawnedDaemonDead(ipfsd)
139154
if (isErrored) { // save daemon output to error.log
140155
logger.error(logs)
156+
if (migrationPrompt) {
157+
migrationPrompt.loadWindow(logs, isErrored, isFinished)
158+
} else {
159+
showMigrationPrompt(logs, isErrored, isFinished)
160+
}
141161
}
142162
}
143163

src/daemon/migration-prompt.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ const inProgressTemplate = (logs, id, done) => {
6464
}
6565

6666
const errorTemplate = (logs) => {
67-
const title = i18n.t('migrationFailedDialog.title')
68-
const message = i18n.t('migrationFailedDialog.message')
67+
const title = i18n.t('startupFailedDialog.title')
68+
const message = i18n.t('startupFailedDialog.message')
6969
const buttons = [
7070
`<button class="default" onclick="javascript:window.close()">${i18n.t('close')}</button>`,
7171
`<button onclick="javascript:openIssue()">${i18n.t('reportTheError')}</button>`

0 commit comments

Comments
 (0)