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

  1. Ensure EnableSiyuanModule completed successfully before dispatching events or requests through JS context paths
  2. Verify each intermediate key in the path exists (e.g. rt.GlobalObject().Get("siyuan") != nil)
  3. Log the full path being resolved to spot the wrong intermediate segment
  4. 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

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


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)