siyuan-note/siyuan · error

path : expected object, got %T

Error message

path %v: expected object, got %T

What it means

While walking the property path, getJsContextValue converts the cursor to an object before reading the next key. If ToObject returns nil — the cursor is a value that cannot be represented as an object for property access — this error reports the key and the cursor's Go type. It flags an unexpected value shape at some point in the requested context path.

Solutions

  1. Inspect the %T in the message to identify what type occupies the path segment
  2. Restore the expected namespace to a proper object (re-run the relevant inject* function)
  3. Validate that each path segment is an object before resolving deeper
  4. Add a pre-check conversion (cursor.ToObject(rt) != nil) in custom dispatch code

Example fix

// before
getJsContextValue(rt, []any{"siyuan", "client"}) // error: expected object, got <nil>
// after
siyuan := rt.GlobalObject().Get("siyuan")
if siyuan == nil || siyuan.ToObject(rt) == nil {
    return fmt.Errorf("siyuan namespace missing")
}
Defensive patterns

Strategy: validation

Validate before calling

siyuan := rt.GlobalObject().Get("siyuan")
if siyuan == nil || siyuan.ToObject(rt) == nil { return errors.New("siyuan namespace is not an object") }

Type guard

func isJSObject(rt *goja.Runtime, v goja.Value) bool {
    return v != nil && !goja.IsUndefined(v) && !goja.IsNull(v) && v.ToObject(rt) != nil
}

Try / catch

v, err := getJsContextValue(rt, paths)
if err != nil {
    logging.LogWarnf("unexpected value in path: %v", err)
    return
}

Prevention

When it happens

Trigger: Calling getJsContextValue where an intermediate value is of a Go/JS type whose ToObject yields nil — e.g. a primitive stub, an empty value produced by a failed earlier conversion, or a host object that refused conversion.

Common situations: A global namespace overwritten with a non-object primitive by plugin code; a host-injected value that failed conversion; path resolution hitting a getter that returned an exotic value.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/bb733b463bc94fd5. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/sandbox.go:304

// 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)
		case int:
			cursor = obj.Get(strconv.Itoa(k))
			path = fmt.Sprintf("%s[%d]", path, k)
		default:
			err = fmt.Errorf("unsupported path type: %T", key)
			return
		}
	}
	value = cursor
	return
}

View on GitHub (pinned to 8641553a1f)