siyuan-note/siyuan · error

failed to serialize config.

Error message

failed to serialize config.%s: %v

What it means

unmarshalCapabilityJSON serializes a JS capability config field (identified by name, e.g. config.effects or config.actionEffects) to JSON before decoding it into a Go struct. When goja's MarshalJSON fails, the error names the field. This means the JS value for that config field cannot be represented as JSON at all.

Solutions

  1. Ensure the named config field is a plain JSON object (string keys, serializable values)
  2. Remove functions, Symbols, and circular references from the object
  3. Sanitize in JS: JSON.parse(JSON.stringify(value)) before passing it
  4. Read the wrapped error to locate the offending value

Example fix

// before
config.actionEffects = { run: { handler: (args) => doSomething() } } // function not serializable

// after
config.actionEffects = { run: { readOnlyHint: false, destructiveHint: true } };
Defensive patterns

Strategy: validation

Validate before calling

function isJsonSerializable(v) {
  try { JSON.stringify(v); return true; } catch { return false; }
}
if (!isJsonSerializable(config.effects)) throw new Error("config.effects must be JSON-serializable");

Try / catch

try {
  registerCapability(config);
} catch (e) {
  if (String(e).includes("failed to serialize config.")) {
    console.error("Capability config contains non-serializable values", e);
  }
}

Prevention

When it happens

Trigger: Passing a non-serializable value as config.effects or config.actionEffects: circular references, functions as values, Symbol keys, or a throwing getter somewhere in the object graph.

Common situations: Plugin authors embed callback functions inside the effects object expecting them to be invoked, or accidentally share a circular config object between plugins; goja marshalling chokes on it.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/7b98a7670c0e5d6b. Report an issue: GitHub.

Appendix: source

Thrown at kernel/plugin/api_agent.go:302

}

func jsCapabilityActionEffectsToGoEffects(rt *goja.Runtime, value goja.Value) (map[string]tools.ToolEffects, error) {
	actionEffects := map[string]tools.ToolEffects{}
	if err := unmarshalCapabilityJSON(rt, value, &actionEffects, "actionEffects"); err != nil {
		return nil, err
	}
	for action := range actionEffects {
		if strings.TrimSpace(action) == "" {
			return nil, fmt.Errorf("config.actionEffects contains an empty action")
		}
	}
	return actionEffects, nil
}

func unmarshalCapabilityJSON(rt *goja.Runtime, value goja.Value, target any, field string) error {
	jsonValue, err := value.ToObject(rt).MarshalJSON()
	if err != nil {
		return fmt.Errorf("failed to serialize config.%s: %v", field, err)
	}
	if err = json.Unmarshal(jsonValue, target); err != nil {
		return fmt.Errorf("invalid config.%s: %v", field, err)
	}
	return nil
}

View on GitHub (pinned to 9f775e8a12)