siyuan-note/siyuan · error

unsupported path type: %T

Error message

unsupported path type: %T

What it means

getJsContextValue walks a path of keys through the plugin's goja JS runtime starting at globalThis. Each path segment must be either a string (property name) or an int (converted to a string index). If a segment is any other Go type, the walk aborts with 'unsupported path type: %T'. This is a programming-error guard in the kernel, not a plugin-facing validation.

Source

Thrown at kernel/plugin/sandbox.go:316

			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
}

// dispatchEvent calls the globalThis.siyuan.event.on hook with the given event object.
func dispatchEvent(p *KernelPlugin, rt *goja.Runtime, e any) (async bool, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("goja panic during dispatchEvent: %v", r)
		}
	}()

	event, err := getJsContextValue(rt, []any{"siyuan", "event"})
	if err != nil {
		return

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Inspect the caller's path slice and change the offending element to a string (or int for array indexes)
  2. If the path is built dynamically, explicitly convert segments with fmt.Sprintf("%v", seg) or a type switch before calling getJsContextValue
  3. If it is your own kernel code, extend the switch in getJsContextValue to accept the new segment type instead of falling through to default

Example fix

// before
paths := []any{"siyuan", "server", scope, requestType} // scope is a custom int-typed enum
// after
paths := []any{"siyuan", "server", string(scope), string(requestType)}
Defensive patterns

Strategy: type-guard

Validate before calling

func validPathSegments(paths []any) bool { for _, p := range paths { switch p.(type) { case string, int: default: return false } } return true }

Type guard

func isPathSegment(k any) bool { switch k.(type) { case string, int: return true }; return false }

Try / catch

if !validPathSegments(paths) { return fmt.Errorf("invalid path segments") }
value, err := getJsContextValue(rt, paths)
if err != nil { return err }

Prevention

When it happens

Trigger: A caller of getJsContextValue (e.g. dispatchEvent with ["siyuan","event"], or getRequestHandler with ["siyuan","server",scope,requestType]) passes a path element that is neither string nor int — e.g. a nil, float64, custom struct, or goja.Value segment.

Common situations: Kernel-side refactors where a path was built dynamically (e.g. fmt.Sprintf result used as a segment, or an enum typed as something other than string); new code reusing getJsContextValue for other lookups with untyped path slices.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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