{"record":{"id":"f2f23e15971fb8ef","repo":"moeru-ai/airi","slug":"previous-godot-stage-process-is-still-shutting-dow","errorCode":null,"errorMessage":"Previous Godot stage process is still shutting down. Retry after it exits.","messagePattern":"Previous Godot stage process is still shutting down\\. Retry after it exits\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/main/services/airi/godot-stage/index.ts","lineNumber":718,"sourceCode":"      return await lifecycleMutex.runExclusive(async () => {\n        let spawnedProcess: GodotStageProcess | undefined\n\n        try {\n          if (currentProcess && currentStatus.state === 'running') {\n            return currentStatus\n          }\n\n          if (currentProcess && currentStatus.state === 'starting' && currentReady) {\n            await currentReady.promise\n            return currentStatus\n          }\n\n          if (currentProcess) {\n            const activeProcess = currentProcess\n            await stopProcessAfterFailedStart()\n\n            if (currentProcess === activeProcess) {\n              throw new Error('Previous Godot stage process is still shutting down. Retry after it exits.')\n            }\n          }\n\n          await stopSocketRuntime()\n\n          const socketRuntime = await startSocketRuntime()\n          const godotBinary = await resolveGodotBinary()\n          const websocketUrl = `ws://127.0.0.1:${socketRuntime.port}/ws?token=${socketRuntime.token}`\n          const readyDeferred = createDeferred<void>()\n          const readyTimeout = setTimeout(() => {\n            readyDeferred.reject(new Error('Godot stage did not report ready in time.'))\n          }, 20_000)\n\n          currentReady = readyDeferred\n          expectedProcessExit = false\n          setStatus({\n            state: 'starting',\n            pid: null,","sourceCodeStart":700,"sourceCodeEnd":736,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/main/services/airi/godot-stage/index.ts#L700-L736","documentation":"Thrown by the start handler inside the lifecycle mutex after it detected an existing currentProcess in a non-'starting' state, called stopProcessAfterFailedStart to tear it down, and then observed currentProcess === activeProcess — meaning the old process handle did not clear during shutdown. The start refuses to proceed to avoid double-process state.","triggerScenarios":"Calling electronGodotStageStart while a previous Godot process handle is still assigned to currentProcess (e.g. a failed prior start whose exit handler hasn't fired), and stopProcessAfterFailedStart did not null out currentProcess before the equality check.","commonSituations":"Repeated start attempts after a failed launch; the Godot child process ignoring SIGTERM and lingering; exit handler that clears currentProcess racing with the restart; rapid start/stop toggling in the UI.","solutions":["Retry electronGodotStageStart after the previous process actually exits (its pid disappears from the process table).","If the Godot child is wedged, kill it externally, then restart.","Ensure stopProcessAfterFailedStart fully awaits process exit and clears currentProcess; if it does not, report it as a lifecycle bug.","Avoid hammering start while a shutdown is in flight; debounce or disable the control until status returns to stopped."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await electronGodotStageStart()\n}\ncatch (error) {\n  if (errorMessageFrom(error)?.startsWith('Previous Godot stage process is still shutting down')) {\n    // wait until status returns 'stopped' and the old pid is gone, then retry\n  }\n}","preventionTips":["Wait for the previous process to fully exit before restarting.","Kill a wedged Godot child externally if it ignores shutdown.","Debounce the start control to avoid hammering during shutdown."],"tags":["godot-stage","lifecycle","process-management","electron","concurrency"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}