siyuan-note/siyuan · error

globalThis.Object.freeze is not a function

Error message

globalThis.Object.freeze is not a function

What it means

ObjectFreeze resolves globalThis.Object and expects its "freeze" property to be a callable JS function. If Object exists but Object.freeze is not a function (e.g. it was overwritten with a non-function value), this error is thrown via goja.AssertFunction. It means the sandbox's Object built-in has been tampered with or stubbed incompletely.

Source

Thrown at kernel/plugin/sandbox.go:132

	lo.Must0(injectServer(p, rt, siyuan))
	lo.Must0(injectSecretsVars(p, rt, siyuan))

	lo.Must0(ObjectFreeze(rt, siyuan))

	lo.Must0(rt.GlobalObject().Set("siyuan", siyuan))
	return
}

// ObjectFreeze calls Object.freeze() on the given goja object.
func ObjectFreeze(rt *goja.Runtime, obj *goja.Object) error {
	Object := rt.GlobalObject().Get("Object").ToObject(rt)
	if Object == nil {
		return fmt.Errorf("globalThis.Object is not an object")
	}

	freeze, ok := goja.AssertFunction(Object.Get("freeze"))
	if !ok {
		return fmt.Errorf("globalThis.Object.freeze is not a function")
	}

	_, err := freeze(Object, obj)
	return err
}

// ObjectSeal calls Object.seal() on the given goja object.
func ObjectSeal(rt *goja.Runtime, obj *goja.Object) error {
	Object := rt.GlobalObject().Get("Object").ToObject(rt)
	if Object == nil {
		return fmt.Errorf("globalThis.Object is not an object")
	}

	seal, ok := goja.AssertFunction(Object.Get("seal"))
	if !ok {
		return fmt.Errorf("globalThis.Object.seal is not a function")
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Restore or avoid overwriting globalThis.Object.freeze in runtime setup code
  2. Order operations so API objects are frozen before any untrusted plugin code runs
  3. If stubbing in tests, stub with a real function: globalThis.Object.freeze = (o) => o
  4. Wrap ObjectFreeze and fall back to skipping the freeze when the built-in is unusable

Example fix

// before
// test setup
rt.RunString("Object.freeze = 1")
plugin.ObjectFreeze(rt, obj) // error: not a function
// after
rt.RunString("const __f = Object.freeze; Object.freeze = (o) => __f(o)")
Defensive patterns

Strategy: type-guard

Validate before calling

o := rt.GlobalObject().Get("Object")
if o != nil {
    if _, ok := goja.AssertFunction(o.ToObject(rt).Get("freeze")); !ok { /* skip or restore */ }
}

Type guard

func canFreeze(rt *goja.Runtime) bool {
    o := rt.GlobalObject().Get("Object")
    if o == nil { return false }
    _, ok := goja.AssertFunction(o.ToObject(rt).Get("freeze"))
    return ok
}

Try / catch

if err := plugin.ObjectFreeze(rt, obj); err != nil {
    logging.LogWarningf("freeze skipped: %v", err)
}

Prevention

When it happens

Trigger: Calling ObjectFreeze on a runtime where globalThis.Object.freeze was reassigned to undefined, null, a plain value, or a non-callable proxy trap result — commonly after plugin code or a polyfill overwrote the built-in.

Common situations: A polyfill or shim that redefined Object without freeze; a security-hardened sandbox replacing freeze with a no-op plain function wrapper of wrong type; test code stubbing Object.freeze incorrectly before the runtime injected API objects.

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/64c0a5a371985038. Report an issue: GitHub.