{"record":{"id":"aafcdc1b206f434f","repo":"moeru-ai/airi","slug":"godot-stage-is-not-running","errorCode":null,"errorMessage":"Godot stage is not running.","messagePattern":"Godot stage is not running\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/main/services/airi/godot-stage/index.ts","lineNumber":476,"sourceCode":"    // Startup failed after spawning Godot; release the child process before\n    // allowing the renderer to retry and create another stage runtime.\n    activeProcess.kill()\n\n    await waitForProcessExit(exitPromise, 2_000)\n  }\n\n  function sendSocketMessage(type: string, payload?: unknown) {\n    if (!currentSocketPeer) {\n      return false\n    }\n\n    currentSocketPeer.send(createSocketEnvelope(type, payload))\n    return true\n  }\n\n  function sendViewRequest(type: 'host.view.patch' | 'host.view.request_snapshot', payload: Record<string, unknown> = {}) {\n    if (currentStatus.state !== 'running') {\n      throw new Error('Godot stage is not running.')\n    }\n\n    const requestId = randomUUID()\n    if (!sendSocketMessage(type, { requestId, ...payload })) {\n      throw new Error('Godot stage bridge is not connected.')\n    }\n\n    return { requestId }\n  }\n\n  function sendSceneInputToGodot(payload: GodotStageSceneApplyPayload) {\n    if (!sendSocketMessage('host.scene.apply', payload)) {\n      throw new Error('Godot stage bridge is not connected.')\n    }\n  }\n\n  function handleSocketMessage(message: GodotStageSocketEnvelope) {\n    switch (message.type) {","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/apps/stage-tamagotchi/src/main/services/airi/godot-stage/index.ts#L458-L494","documentation":"Thrown by sendViewRequest (used by applyViewPatch / requestViewSnapshot) when currentStatus.state !== 'running'. The Godot stage must be in the running state for view mutations to be sent; any earlier state (idle/starting/stopped/errored) causes this guard to throw before issuing a request id.","triggerScenarios":"Calling electronGodotStageApplyViewPatch or electronGodotStageRequestViewSnapshot before the stage has reported 'stage.ready', after it was stopped, or after it crashed.","commonSituations":"Renderer issues a view patch immediately at startup before the Godot process finishes booting; calling after stop(); calling after a stage crash where state flipped to 'errored'/'stopped'; race where the ready deferred hasn't resolved.","solutions":["Await electronGodotStageStart and wait until electronGodotStageGetStatus returns state 'running' before issuing view requests.","Subscribe to electronGodotStageStatusChanged and gate view calls on the running state.","After a stop or error, restart the stage before retrying view operations.","Handle the thrown error in the renderer and surface a 'stage not ready' UI instead of retrying blindly."],"exampleFix":"// before\nawait electronGodotStageApplyViewPatch({ patches })\n\n// after\nconst status = await electronGodotStageGetStatus()\nif (status.state !== 'running') {\n  await electronGodotStageStart()\n}\nawait electronGodotStageApplyViewPatch({ patches })","handlingStrategy":"validation","validationCode":"async function stageIsRunning(): Promise<boolean> {\n  return (await electronGodotStageGetStatus()).state === 'running'\n}","typeGuard":"async function stageIsRunning(): Promise<boolean> {\n  return (await electronGodotStageGetStatus()).state === 'running'\n}","tryCatchPattern":null,"preventionTips":["Subscribe to electronGodotStageStatusChanged and gate view calls on 'running'.","Await start and readiness before issuing view patches.","Restart the stage after stop/error before retrying."],"tags":["godot-stage","lifecycle","ipc","electron","state-machine"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}