{"record":{"id":"cdbbffa033dc0de1","repo":"siyuan-note/siyuan","slug":"globalthis-siyuan-plugin-lifecycle-not-found","errorCode":null,"errorMessage":"globalThis.siyuan.plugin.lifecycle not found","messagePattern":"globalThis\\.siyuan\\.plugin\\.lifecycle not found","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/plugin.go","lineNumber":866,"sourceCode":"\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"panic during lifecycle hook invocation: %v\", r)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tlogging.LogErrorf(\"[plugin:%s] lifecycle hook [%q] error: %v\", p.Name, name, err)\n\t\t}\n\t}()\n\n\tdone := make(chan TaskResult, 1)\n\n\trunErr := p.worker.Run(func(rt *goja.Runtime) (_ any, err error) {\n\t\tlifecycle, err := getJsContextValue(rt, []any{\"siyuan\", \"plugin\", \"lifecycle\"})\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t\tif lifecycle == nil {\n\t\t\terr = fmt.Errorf(\"globalThis.siyuan.plugin.lifecycle not found\")\n\t\t\treturn\n\t\t}\n\n\t\tpluginObj := lifecycle.ToObject(rt)\n\t\tif pluginObj == nil {\n\t\t\terr = fmt.Errorf(\"globalThis.siyuan.plugin.lifecycle is not an object\")\n\t\t\treturn\n\t\t}\n\n\t\thookValue := pluginObj.Get(name)\n\t\thook, ok := goja.AssertFunction(hookValue)\n\t\tif !ok {\n\t\t\terr = fmt.Errorf(\"globalThis.siyuan.plugin.lifecycle.%s not bound to a function\", name)\n\t\t\treturn\n\t\t}\n\n\t\tinvokeFunction(func(_ *goja.Runtime, result *CallResult) {\n\t\t\tdone <- *result.TaskResult()","sourceCodeStart":848,"sourceCodeEnd":884,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/plugin/plugin.go#L848-L884","documentation":"During hook invocation the kernel resolves the path globalThis.siyuan.plugin.lifecycle inside the plugin's goja runtime via getJsContextValue. If the value is undefined/null the runtime is told to run the hook anyway and fails fast with this error: the plugin never installed its lifecycle object, so no hooks can be dispatched.","triggerScenarios":"Calling invokeHook/lifecycle dispatch when the plugin's JS entry script did not (successfully) assign globalThis.siyuan.plugin.lifecycle - e.g. the script errored mid-execution or was never registered.","commonSituations":"A plugin entry file that failed to load earlier (syntax error, missing export) leaving the context unset; a plugin written for a different host (no `siyuan` global); truncated or corrupted plugin dist files.","solutions":["Check earlier logs for JS load/compile errors from the plugin entry - fix the root script failure first","Ensure the plugin assigns globalThis.siyuan.plugin.lifecycle (or registers via the official plugin scaffold) before hooks fire","Reinstall/rebuild the plugin so its entry file is complete and compatible with the kernel API","Verify the entry script actually ran: add a console log at the top of the plugin entry and check plugin logs"],"exampleFix":"// plugin entry (before)\nexport default class { onload() {} } // never attached to siyuan.plugin.lifecycle\n// after\nglobalThis.siyuan = globalThis.siyuan || {}\nglobalThis.siyuan.plugin = globalThis.siyuan.plugin || {}\nglobalThis.siyuan.plugin.lifecycle = new (class { onload() {} onunload() {} })()","handlingStrategy":"validation","validationCode":"// plugin JS entry must end with something like:\nif (!globalThis.siyuan?.plugin?.lifecycle) {\n  throw new Error('entry failed to install siyuan.plugin.lifecycle')\n}","typeGuard":"func lifecycleInstalled(rt *goja.Runtime) bool {\n  v, err := getJsContextValue(rt, []any{\"siyuan\", \"plugin\", \"lifecycle\"})\n  return err == nil && v != nil\n}","tryCatchPattern":"if err := dispatchHook(\"onload\"); err != nil {\n  if strings.Contains(err.Error(), \"lifecycle not found\") {\n    logging.LogErrorf(\"plugin entry did not register lifecycle; disabling plugin\")\n    // disable or quarantine the plugin\n  }\n}","preventionTips":["Use the official plugin scaffold so globalThis.siyuan.plugin.lifecycle is always installed","Check kernel logs for earlier entry-script compile errors - this error is usually downstream","Verify the plugin entry file exists and is complete after install/update","Add a self-check at the end of the plugin entry that asserts the lifecycle object"],"tags":["plugin","goja","lifecycle","javascript"],"backgroundTag":"resource-not-found","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}