{"record":{"id":"a9c90c5f37f4a7de","repo":"siyuan-note/siyuan","slug":"globalthis-object-seal-is-not-a-function","errorCode":null,"errorMessage":"globalThis.Object.seal is not a function","messagePattern":"globalThis\\.Object\\.seal is not a function","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/sandbox.go","lineNumber":148,"sourceCode":"\tfreeze, ok := goja.AssertFunction(Object.Get(\"freeze\"))\n\tif !ok {\n\t\treturn fmt.Errorf(\"globalThis.Object.freeze is not a function\")\n\t}\n\n\t_, err := freeze(Object, obj)\n\treturn err\n}\n\n// ObjectSeal calls Object.seal() on the given goja object.\nfunc ObjectSeal(rt *goja.Runtime, obj *goja.Object) error {\n\tObject := rt.GlobalObject().Get(\"Object\").ToObject(rt)\n\tif Object == nil {\n\t\treturn fmt.Errorf(\"globalThis.Object is not an object\")\n\t}\n\n\tseal, ok := goja.AssertFunction(Object.Get(\"seal\"))\n\tif !ok {\n\t\treturn fmt.Errorf(\"globalThis.Object.seal is not a function\")\n\t}\n\n\t_, err := seal(Object, obj)\n\treturn err\n}\n\n// ObjectSetDataMethods attaches text(), json(), buffer() and arrayBuffer() methods to a JS object,\n// each returning a Promise that resolves with the corresponding representation of data.\nfunc ObjectSetDataMethods(p *KernelPlugin, rt *goja.Runtime, object *goja.Object, data []byte) (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"ObjectSetDataMethods: %v\", r)\n\t\t}\n\t}()\n\n\tlo.Must0(object.Set(\"text\", rt.ToValue(func(call goja.FunctionCall, rt *goja.Runtime) goja.Value {\n\t\tpromise, resolve, reject := rt.NewPromise()\n","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/plugin/sandbox.go#L130-L166","documentation":"ObjectSeal resolves globalThis.Object and requires its \"seal\" property to be a callable function. If Object exists but Object.seal was replaced by a non-function value, goja.AssertFunction fails and this error is thrown. It indicates the Object built-in was partially overwritten or incompletely stubbed.","triggerScenarios":"Calling ObjectSeal on a runtime where globalThis.Object.seal was reassigned to undefined, a number, an object, or a non-callable value — typically by plugin code, a polyfill, or an incorrect test stub.","commonSituations":"Test doubles that stubbed Object.seal as a plain value; polyfills redefining Object wholesale; hardening scripts that replaced seal with metadata instead of a function.","solutions":["Restore globalThis.Object.seal to a function before injection","Seal API objects before untrusted code runs so built-ins cannot be overwritten first","In tests, stub with a callable: Object.seal = (o) => o","Catch the error and degrade gracefully (skip sealing) rather than failing plugin load"],"exampleFix":"// before\nrt.RunString(\"Object.seal = undefined\")\nplugin.ObjectSeal(rt, obj) // error: not a function\n// after\nrt.RunString(\"Object.seal = Object.seal || ((o) => o)\")","handlingStrategy":"type-guard","validationCode":"o := rt.GlobalObject().Get(\"Object\")\nif o != nil {\n    if _, ok := goja.AssertFunction(o.ToObject(rt).Get(\"seal\")); !ok { /* skip or restore */ }\n}","typeGuard":"func canSeal(rt *goja.Runtime) bool {\n    o := rt.GlobalObject().Get(\"Object\")\n    if o == nil { return false }\n    _, ok := goja.AssertFunction(o.ToObject(rt).Get(\"seal\"))\n    return ok\n}","tryCatchPattern":"if err := plugin.ObjectSeal(rt, obj); err != nil {\n    logging.LogWarningf(\"seal skipped: %v\", err)\n}","preventionTips":["Never reassign Object.seal to a non-function","Seal before executing untrusted code","Use callable stubs in tests"],"tags":["goja","javascript","object-seal","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-14T00:17:10.932Z"}