{"record":{"id":"db4f2b27df69a683","repo":"siyuan-note/siyuan","slug":"path-v-value-is-nil","errorCode":null,"errorMessage":"path %v: value is nil","messagePattern":"path (.+?): value is nil","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/sandbox.go","lineNumber":293,"sourceCode":"}\n\n// NewDataObject creates a new JS object with text(), json(), buffer() and arrayBuffer() methods for the given data.\nfunc NewDataObject(p *KernelPlugin, rt *goja.Runtime, data []byte) (*goja.Object, error) {\n\tobj := rt.NewObject()\n\tif err := ObjectSetDataMethods(p, rt, obj, data); err != nil {\n\t\treturn nil, err\n\t}\n\treturn obj, nil\n}\n\n// getJsContextValue safely retrieves a nested value from the plugin's JS context, returning nil if any step fails.\nfunc getJsContextValue(rt *goja.Runtime, paths []any) (value goja.Value, err error) {\n\tvar cursor goja.Value = rt.GlobalObject()\n\tvar path string = \"globalThis\"\n\n\tfor _, key := range paths {\n\t\tif cursor == nil {\n\t\t\terr = fmt.Errorf(\"path %v: value is nil\", key)\n\t\t\treturn\n\t\t}\n\n\t\tif goja.IsUndefined(cursor) || goja.IsNull(cursor) {\n\t\t\terr = fmt.Errorf(\"path %v: value is %s\", key, cursor.String())\n\t\t\treturn\n\t\t}\n\n\t\tobj := cursor.ToObject(rt)\n\t\tif obj == nil {\n\t\t\terr = fmt.Errorf(\"path %v: expected object, got %T\", key, cursor)\n\t\t\treturn\n\t\t}\n\n\t\tswitch k := key.(type) {\n\t\tcase string:\n\t\t\tcursor = obj.Get(k)\n\t\t\tpath = fmt.Sprintf(\"%s.%s\", path, k)","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/plugin/sandbox.go#L275-L311","documentation":"getJsContextValue walks a path (e.g. [\"siyuan\",\"client\",\"request\"]) down from globalThis to resolve a JS value for event dispatch or request handling. Before dereferencing each key it checks the current cursor; a nil cursor means some earlier step produced a nil value that cannot be traversed, so this error names the offending key. It indicates the expected intermediate object in the global context does not exist in a traversable form.","triggerScenarios":"Calling getJsContextValue (via dispatchEvent or getRequestHandler) with a path whose intermediate value resolved to nil — e.g. the siyuan global was never injected, or a previous Get returned nil that ToObject turned into nil for the next hop.","commonSituations":"Dispatching an event before EnableSiyuanModule finished injection; a plugin referencing an API namespace that was removed or renamed; handler paths built dynamically with a typo'd intermediate key.","solutions":["Ensure EnableSiyuanModule completed successfully before dispatching events or requests through JS context paths","Verify each intermediate key in the path exists (e.g. rt.GlobalObject().Get(\"siyuan\") != nil)","Log the full path being resolved to spot the wrong intermediate segment","Guard callers: skip dispatch/handling when the target namespace is not injected"],"exampleFix":"// before\ngetJsContextValue(rt, []any{\"siyuan\", \"events\", \"emit\"}) // error: path siyuan: value is nil\n// after\nif rt.GlobalObject().Get(\"siyuan\") == nil {\n    return // siyuan module not injected\n}\ngetJsContextValue(rt, []any{\"siyuan\", \"events\", \"emit\"})","handlingStrategy":"validation","validationCode":"for _, seg := range path {\n    v := rt.GlobalObject().Get(fmt.Sprintf(\"%v\", seg))\n    if v == nil { return fmt.Errorf(\"path segment missing: %v\", seg) }\n}","typeGuard":null,"tryCatchPattern":"v, err := getJsContextValue(rt, paths)\nif err != nil {\n    logging.LogWarnf(\"context path unresolved: %v\", err)\n    return\n}","preventionTips":["Ensure EnableSiyuanModule succeeded before dispatching through JS paths","Validate intermediate path segments exist before deep resolution","Log the full path on failure to spot typos"],"tags":["goja","context-path","plugin-sandbox","null-value"],"backgroundTag":"null-argument","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}