{"record":{"id":"9097a0e1a81d2988","repo":"siyuan-note/siyuan","slug":"panic-during-siyuan-client-event-v","errorCode":null,"errorMessage":"panic during siyuan.client.event: %v","messagePattern":"panic during siyuan\\.client\\.event: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/api_client.go","lineNumber":697,"sourceCode":"\t\t\tlo.Must0(esObj.Set(\"readyState\", rt.ToValue(readyState.Load())))\n\t\t\tlo.Must0(esObj.Set(\"url\", rt.ToValue(path)))\n\n\t\t\tlo.Must0(esObj.Set(\"onopen\", goja.Null()))\n\t\t\tlo.Must0(esObj.Set(\"onmessage\", goja.Null()))\n\t\t\tlo.Must0(esObj.Set(\"onclose\", goja.Null()))\n\t\t\tlo.Must0(esObj.Set(\"onerror\", goja.Null()))\n\n\t\t\tlo.Must0(esObj.Set(\"close\", es_close))\n\n\t\t\tlo.Must0(ObjectSeal(rt, esObj))\n\n\t\t\tsetReadyState(EventSourceConnecting)\n\n\t\t\tgo func() {\n\t\t\t\tvar err error\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r != nil {\n\t\t\t\t\t\terr = fmt.Errorf(\"panic during siyuan.client.event: %v\", r)\n\t\t\t\t\t}\n\n\t\t\t\t\tdoClose()\n\n\t\t\t\t\tp.worker.Run(func(rt *goja.Runtime) (_ any, _ error) {\n\t\t\t\t\t\tif err != nil && !errors.Is(err, context.Canceled) {\n\t\t\t\t\t\t\tevent := rt.NewObject()\n\t\t\t\t\t\t\tevent.Set(\"type\", rt.ToValue(\"error\"))\n\t\t\t\t\t\t\tevent.Set(\"error\", rt.NewGoError(err))\n\t\t\t\t\t\t\tinvokeEsHook(\"onerror\", event)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif EventSourceState(readyState.Load()) != EventSourceClosed {\n\t\t\t\t\t\t\tsetReadyState(EventSourceClosed)\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn\n\t\t\t\t\t}, nil)\n\t\t\t\t}()\n","sourceCodeStart":679,"sourceCodeEnd":715,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/plugin/api_client.go#L679-L715","documentation":"A panic was recovered inside the SSE subscription goroutine of siyuan.client.event. The %v is the recovered value. This is an internal runtime failure during the SSE read loop, not a caller argument error (those are caught before the goroutine starts).","triggerScenarios":"A bug in the SSE client, the goja runtime, or a race during plugin unload while subscribed. The recover in the goroutine's defer converts the panic into an onerror event.","commonSituations":"Plugin hot-reload or kernel shutdown during an active SSE stream, or a version-specific bug in the SSE library.","solutions":["Check the kernel log for the recovered panic and report it with the plugin name.","Ensure the plugin is not unloaded while the EventSource is open (call es.close() first).","Update kernel/plugin runtime to the latest version."],"exampleFix":"const es = await siyuan.client.event('/events/foo');\nes.onerror = (e) => {\n  if (String(e.error).includes('panic during')) {\n    // internal failure; optionally recreate the EventSource\n  }\n};","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"es.onerror = (ev) => {\n  const msg = String(ev?.error ?? '');\n  if (msg.includes('panic during')) { /* log; optionally reconnect via new event() */ }\n};","preventionTips":["Always call es.close() before unloading the plugin.","Implement onerror to surface internal failures.","Keep runtime versions current."],"tags":["client-event","eventsource","panic","internal"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}