{"record":{"id":"e482f9c04f840b19","repo":"datawhalechina/hello-agents","slug":"error-e482f9","errorCode":null,"errorMessage":"消息发送失败","messagePattern":"消息发送失败","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Co-creation-projects/afei-GuessWhoAmI/frontend/app.js","lineNumber":117,"sourceCode":"      return;\n    }\n\n    input.value = '';\n    this.addMessage(message, 'user');\n    this.setControlsDisabled(true);\n\n    try {\n      const response = await fetch('http://localhost:8000/api/game/chat', {\n        method: 'POST',\n        headers: {'Content-Type': 'application/json'},\n        body: JSON.stringify({session_id: this.sessionId, message: message})\n      });\n\n      if (!response.ok) throw new Error(`HTTP error: ${response.status}`);\n\n      const result = await response.json();\n\n      if (!result.success) throw new Error(result.error || '消息发送失败');\n\n      const data = result.data;\n      this.addMessage(data.response, 'agent');\n\n      // Update remaining questions from server\n      this.remainingQuestions = data.remaining_questions;\n      this.updateStats();\n\n      if (data.is_game_over) {\n        this.endGame(false);\n      }\n\n    } catch (error) {\n      this.addMessage(`⚠️ 发送失败：${error.message}`, 'agent');\n      console.error('Send message error:', error);\n    } finally {\n      this.setControlsDisabled(false);\n    }","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/afei-GuessWhoAmI/frontend/app.js#L99-L135","documentation":"Application-logic guard for POST /api/game/chat: HTTP was 2xx and JSON parsed, but result.success is falsy. Throws the backend's result.error, falling back to '消息发送失败' when the backend omits the error field. Means the chat turn was rejected at the business layer — most commonly an invalid/expired session_id or game already over.","triggerScenarios":"Backend returns success:false with no error field for conditions like unknown session_id, game finished, question budget exhausted, or message content rejected. The literal fallback masks the actual reason.","commonSituations":"Session expired server-side while the tab stayed open; backend developer forgot to set error when returning success:false; envelope drift after refactor.","solutions":["Log result on failure and fix the backend to always include a descriptive error string","On session-invalid errors, restart the game automatically","Align frontend fallback text with likely causes and surface result for support","Add backend tests asserting error is present whenever success is false"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!this.sessionId) { await this.startNewGame(); }","typeGuard":"function isChatResult(r) { return r && typeof r.success === 'boolean' && (!r.success || ('data' in r && 'response' in r.data)); }","tryCatchPattern":"try { ... } catch (e) { alert(`消息发送失败：${e.message}`); this.setControlsDisabled(false); }","preventionTips":["Require backend to return descriptive error strings","Re-check session validity before sending","Reset control disabled state in finally so UI stays usable"],"tags":["api-envelope","chat","session","game"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}