siyuan-note/siyuan · error
config.actionEffects contains an empty action
Error message
config.actionEffects contains an empty action
What it means
Thrown by jsCapabilityActionEffectsToGoEffects after successfully unmarshaling the actionEffects map — one or more keys (action names) in the map are empty or whitespace-only after strings.TrimSpace. Action names are used as identifiers in the declared effects map, so empty keys would be ambiguous.
Source
Thrown at kernel/plugin/api_agent.go:293
return
}
func jsCapabilityEffectsToGoEffects(rt *goja.Runtime, value goja.Value) (*tools.ToolEffects, error) {
effects := &tools.ToolEffects{}
if err := unmarshalCapabilityJSON(rt, value, effects, "effects"); err != nil {
return nil, err
}
return effects, nil
}
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
- Remove empty or whitespace-only keys from the actionEffects map before passing it
- Validate action names are non-empty when constructing the actionEffects object
Example fix
// before
const actionEffects = {
'': { writes: ['blocks'] },
'create': { writes: ['blocks'] }
};
await siyuan.agent.registerCapability('myTool', {
description: '...',
inputSchema: { type: 'object' },
actionEffects
}, handler);
// after
const actionEffects = {
'create': { writes: ['blocks'] }
}; Defensive patterns
Strategy: validation
Validate before calling
// Remove empty action keys before passing
if (config.actionEffects) {
for (const key of Object.keys(config.actionEffects)) {
if (key.trim() === '') {
delete config.actionEffects[key];
}
}
} Type guard
function hasNoEmptyActionKeys(actionEffects) {
if (!actionEffects) return true;
return Object.keys(actionEffects).every(k => k.trim().length > 0);
} Prevention
- Filter out empty action names when constructing the actionEffects map
- Validate action name sources (user input, document data) for emptiness
When it happens
Trigger: Passing config.actionEffects = { '': {...} } or config.actionEffects = { ' ': {...} } — a map with at least one empty/whitespace key. This can happen when action names are dynamically generated from data and one source value is empty.
Common situations: Plugin generates action names from user input or document data that may be empty; a default empty-string key was accidentally included; the actionEffects map was built from a list that contained an empty element.
Related errors
- invalid config.%s: %v
- registerCapability requires 3 arguments: name, config, handl
- config.description must not be empty
- config.description is required and must be a string
- config.inputSchema is required
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/7fae83b9c306f202.
Report an issue: GitHub.