siyuan-note/siyuan · error
failed to serialize config.%s: %v
Error message
failed to serialize config.%s: %v
What it means
Thrown by unmarshalCapabilityJSON when MarshalJSON fails on the JS value representing config.effects or config.actionEffects. This is the same serialization failure as error 974 but for the effects/actionEffects fields — the value contains non-serializable content like functions or circular references.
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 251596fc0d)
Solutions
- Ensure the effects/actionEffects value is a plain JSON-serializable object
- Strip non-serializable properties with JSON.parse(JSON.stringify(value)) before passing
- Construct the effects object from plain data, not from class instances with methods
Example fix
// before
const effects = {
writes: ['blocks'],
validate: () => true // function — not serializable
};
await siyuan.agent.registerCapability('myTool', {
description: '...',
inputSchema: { type: 'object' },
effects
}, handler);
// after
const effects = {
writes: ['blocks']
}; Defensive patterns
Strategy: validation
Validate before calling
// Strip non-serializable properties from effects
if (config.effects) {
config.effects = JSON.parse(JSON.stringify(config.effects));
}
if (config.actionEffects) {
config.actionEffects = JSON.parse(JSON.stringify(config.actionEffects));
} Type guard
function isJsonSerializable(obj) {
try {
JSON.stringify(obj);
return true;
} catch {
return false;
}
} Try / catch
try {
await siyuan.agent.registerCapability(name, config, handler);
} catch (e) {
if (e.message.includes('serialize config.')) {
if (config.effects) config.effects = JSON.parse(JSON.stringify(config.effects));
if (config.actionEffects) config.actionEffects = JSON.parse(JSON.stringify(config.actionEffects));
}
} Prevention
- Build effects objects from plain data, not class instances
- Sanitize with JSON.parse(JSON.stringify()) to strip non-serializable members
When it happens
Trigger: Passing config.effects or config.actionEffects that contains function values, circular references, or symbols. For example, effects = { writes: ['blocks'], compute: () => [] } where 'compute' cannot be JSON-serialized.
Common situations: Plugin includes methods or getters on the effects object; the effects object shares references creating cycles; a builder pattern left intermediate state on the object.
Related errors
- failed to serialize inputSchema: %v
- config.actionEffects contains an empty action
- invalid config.%s: %v
- registerCapability requires 3 arguments: name, config, handl
- first argument must be a tool name string
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/7b98a7670c0e5d6b.
Report an issue: GitHub.