siyuan-note/siyuan · error
path : value is nil
Error message
path %v: value is nil
What it means
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.
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
Example fix
// before
getJsContextValue(rt, []any{"siyuan", "events", "emit"}) // error: path siyuan: value is nil
// after
if rt.GlobalObject().Get("siyuan") == nil {
return // siyuan module not injected
}
getJsContextValue(rt, []any{"siyuan", "events", "emit"}) Defensive patterns
Strategy: validation
Validate before calling
for _, seg := range path {
v := rt.GlobalObject().Get(fmt.Sprintf("%v", seg))
if v == nil { return fmt.Errorf("path segment missing: %v", seg) }
} Try / catch
v, err := getJsContextValue(rt, paths)
if err != nil {
logging.LogWarnf("context path unresolved: %v", err)
return
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- path : expected object, got %T
- path : value is
- expected promise object, got %T
- failed to enable extend modules
- failed to inject global context
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/db4f2b27df69a683.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/plugin/sandbox.go:293
}
// NewDataObject creates a new JS object with text(), json(), buffer() and arrayBuffer() methods for the given data.
func NewDataObject(p *KernelPlugin, rt *goja.Runtime, data []byte) (*goja.Object, error) {
obj := rt.NewObject()
if err := ObjectSetDataMethods(p, rt, obj, data); err != nil {
return nil, err
}
return obj, nil
}
// getJsContextValue safely retrieves a nested value from the plugin's JS context, returning nil if any step fails.
func getJsContextValue(rt *goja.Runtime, paths []any) (value goja.Value, err error) {
var cursor goja.Value = rt.GlobalObject()
var path string = "globalThis"
for _, key := range paths {
if cursor == nil {
err = fmt.Errorf("path %v: value is nil", key)
return
}
if goja.IsUndefined(cursor) || goja.IsNull(cursor) {
err = fmt.Errorf("path %v: value is %s", key, cursor.String())
return
}
obj := cursor.ToObject(rt)
if obj == nil {
err = fmt.Errorf("path %v: expected object, got %T", key, cursor)
return
}
switch k := key.(type) {
case string:
cursor = obj.Get(k)
path = fmt.Sprintf("%s.%s", path, k)View on GitHub (pinned to 8641553a1f)