{"record":{"id":"6874b94eb515f031","repo":"siyuan-note/siyuan","slug":"plugin-lifecycle-has-ended","errorCode":null,"errorMessage":"Plugin lifecycle has ended","messagePattern":"Plugin lifecycle has ended","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/plugin/kernel.ts","lineNumber":169,"sourceCode":"                    });\n                }\n            }\n        });\n        return ws;\n    }\n\n    #createJsonRpcCallUrl() {\n        const searchParams = new URLSearchParams({ name: this.#name, appId: this.#appId });\n        return `api/plugin/rpc?${searchParams.toString()}`;\n    }\n\n    #generateId(): TJsonRpcId {\n        return Lute.NewNodeID();\n    }\n\n    async #fetchRpc(body: string): Promise<any> {\n        if (this.#destroyed) {\n            throw new Error(\"Plugin lifecycle has ended\");\n        }\n        for (let retry = 0; ; retry++) {\n            if (this.#destroyed) {\n                throw new Error(\"Plugin lifecycle has ended\");\n            }\n            const response = await fetch(this.#rpcCallUrl, {\n                method: \"POST\",\n                headers: { \"Content-Type\": \"application/json\" },\n                body,\n            });\n            if (response.status === 204) {\n                return;\n            }\n\n            const data = await response.json();\n            const code = data.error?.code;\n            if ((code !== -32001 && code !== -32002) || retry >= KERNEL_PLUGIN_START_RETRY_COUNT) {\n                return data;","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/app/src/plugin/kernel.ts#L151-L187","documentation":"KernelPluginClient #fetchRpc precondition: an RPC request was attempted after this plugin client was destroyed (#destroyed flag set). The plugin's lifecycle has ended, so no further JSON-RPC calls over api/plugin/rpc are accepted; re-checked inside the retry loop so in-flight requests abort too.","triggerScenarios":"Thrown at app/src/plugin/kernel.ts:169 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Stop issuing RPC calls after plugin unload/disable","Propagate the rejection so pending promises settle instead of retrying","Re-enable the plugin to obtain a fresh, non-destroyed client"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}