{"record":{"id":"bb733b463bc94fd5","repo":"siyuan-note/siyuan","slug":"path-v-expected-object-got-t","errorCode":null,"errorMessage":"path %v: expected object, got %T","messagePattern":"path (.+?): expected object, got %T","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/sandbox.go","lineNumber":304,"sourceCode":"// 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)\n\t\tcase int:\n\t\t\tcursor = obj.Get(strconv.Itoa(k))\n\t\t\tpath = fmt.Sprintf(\"%s[%d]\", path, k)\n\t\tdefault:\n\t\t\terr = fmt.Errorf(\"unsupported path type: %T\", key)\n\t\t\treturn\n\t\t}\n\t}\n\tvalue = cursor\n\treturn\n}","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/plugin/sandbox.go#L286-L322","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the %T in the message to identify what type occupies the path segment","Restore the expected namespace to a proper object (re-run the relevant inject* function)","Validate that each path segment is an object before resolving deeper","Add a pre-check conversion (cursor.ToObject(rt) != nil) in custom dispatch code"],"exampleFix":"// before\ngetJsContextValue(rt, []any{\"siyuan\", \"client\"}) // error: expected object, got <nil>\n// after\nsiyuan := rt.GlobalObject().Get(\"siyuan\")\nif siyuan == nil || siyuan.ToObject(rt) == nil {\n    return fmt.Errorf(\"siyuan namespace missing\")\n}","handlingStrategy":"validation","validationCode":"siyuan := rt.GlobalObject().Get(\"siyuan\")\nif siyuan == nil || siyuan.ToObject(rt) == nil { return errors.New(\"siyuan namespace is not an object\") }","typeGuard":"func isJSObject(rt *goja.Runtime, v goja.Value) bool {\n    return v != nil && !goja.IsUndefined(v) && !goja.IsNull(v) && v.ToObject(rt) != nil\n}","tryCatchPattern":"v, err := getJsContextValue(rt, paths)\nif err != nil {\n    logging.LogWarnf(\"unexpected value in path: %v\", err)\n    return\n}","preventionTips":["Inspect the %T in the message to identify the offending value","Re-run the relevant inject* function if a namespace was overwritten","Validate each segment is an object before deeper traversal"],"tags":["goja","context-path","type-mismatch","plugin-sandbox"],"backgroundTag":"type-mismatch","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"}