{"record":{"id":"0d3251d61e9f0c10","repo":"siyuan-note/siyuan","slug":"window-siyuan-languages-kernel-28-or-data-msg-data-message","errorCode":null,"errorMessage":"window.siyuan.languages._kernel[28] or data.msg/data.message from failed response","messagePattern":"window\\.siyuan\\.languages\\._kernel\\[28\\] or data\\.msg/data\\.message from failed response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/ai/editorSSE.ts","lineNumber":110,"sourceCode":"    onEvent: (event: TAIEditorSSEEvent) => void,\n    signal: AbortSignal,\n) => {\n    const response = await fetch(\"/api/ai/editor/chat\", {\n        method: \"POST\",\n        headers: {\"Content-Type\": \"application/json\"},\n        body: JSON.stringify(request),\n        signal,\n    });\n    const contentType = response.headers.get(\"Content-Type\") || \"\";\n    if (!response.ok || !contentType.includes(\"text/event-stream\")) {\n        let message = window.siyuan.languages._kernel[28];\n        try {\n            const data = await response.json();\n            message = data?.msg || data?.message || message;\n        } catch (e) {\n            // 响应不是 JSON 时使用统一错误文案。\n        }\n        throw new Error(message);\n    }\n    const reader = response.body?.getReader();\n    if (!reader) {\n        throw new Error(window.siyuan.languages._kernel[28]);\n    }\n    const decoder = new TextDecoder();\n    const parserState = createAIEditorSSEParserState();\n    let terminalReceived = false;\n    while (true) {\n        const result = await reader.read();\n        if (result.done) {\n            break;\n        }\n        parseAIEditorSSE(parserState, decoder.decode(result.value, {stream: true})).forEach(event => {\n            terminalReceived = terminalReceived || event.type === \"done\" || event.type === \"error\";\n            onEvent(event);\n        });\n    }","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/app/src/ai/editorSSE.ts#L92-L128","documentation":"fetchAIEditorSSE throws a generic error when the AI editor streaming response is not OK. It first tries to extract a message from the response body's `msg` or `message` JSON fields, falling back to `window.siyuan.languages._kernel[28]` (a localized network/parse failure string) when the body is not JSON. This surfaces backend failure reasons to the UI in a uniform way.","triggerScenarios":"The kernel returns a non-OK HTTP response to an AI editor SSE request and the JSON body has neither `msg` nor `message`, or the body is not JSON at all (e.g. an HTML error page from a proxy, or an empty body).","commonSituations":"AI backend unreachable or misconfigured behind a reverse proxy that returns HTML 502/504 pages; API key missing so the kernel returns a JSON error without `msg`; gateway timeouts returning empty bodies.","solutions":["Check the network tab / kernel logs for the actual HTTP status and response body of the AI request","Verify the AI provider configuration (API key, base URL, model) in Settings - AI","If behind a proxy, ensure it passes through JSON error bodies rather than HTML error pages","Retry the request; transient backend outages commonly produce this"],"exampleFix":"// before: backend returns HTML error page -> message falls back to generic i18n string\n// after: surface status code too\nconst data = await response.json().catch(() => null);\nmessage = data?.msg || data?.message || `AI request failed with status ${response.status}`;","handlingStrategy":"try-catch","validationCode":"if (!window.siyuan.config?.ai) { throw new Error(\"AI is not configured\"); }","typeGuard":"const isFailedResponse = (data: unknown): data is {msg?: string; message?: string} => typeof data === \"object\" && data !== null && (\"msg\" in data || \"message\" in data);","tryCatchPattern":"try {\n    await fetchAIEditorSSE(url, data, onEvent);\n} catch (e) {\n    showMessage(e.message || window.siyuan.languages._kernel[28]); // surface and offer retry\n}","preventionTips":["Validate AI configuration before issuing requests","Avoid proxies that replace JSON errors with HTML pages","Monitor kernel logs for AI backend failures"],"tags":["ai","network","error-message"],"backgroundTag":"http-error-response","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}