siyuan-note/siyuan · warning
AI editor action must not be empty
Error message
AI editor action must not be empty
What it means
SaveAIEditorAction persists an AI editor action (custom prompt action for the editor). It rejects a nil action or one where both Name and Action are empty, since such an entry would be meaningless and unusable in the UI. This is a pure input-validation guard before any storage work.
Solutions
- Provide a non-empty `name` and/or `action` prompt text in the request payload
- Validate the payload client-side before POSTing (check at least one of name/action is non-empty)
- If updating an existing action, load it first via the list API and modify fields rather than sending a bare {id}
Example fix
// before
fetchPost("/api/ai/editor/action/save", { id: existing.id })
// after
if (!existing.name && !existing.action) throw new Error("name or action is required")
fetchPost("/api/ai/editor/action/save", { id: existing.id, name: existing.name, action: existing.action }) Defensive patterns
Strategy: validation
Validate before calling
if (!action || (!action.name && !action.action)) {
throw new Error("AI editor action requires a non-empty name or action");
} Type guard
const isValidAction = (a) => !!a && (typeof a.name === "string" && a.name.trim() !== "" || typeof a.action === "string" && a.action.trim() !== "");
Try / catch
try {
await fetchPost("/api/ai/editor/action/save", action);
} catch (e) {
if (e.message.includes("must not be empty")) showMsg("Name or action prompt is required");
} Prevention
- Require at least the action prompt field in UI forms
- Trim inputs before submitting
- Never send a bare {id} payload for updates
When it happens
Trigger: Calling SaveAIEditorAction (saveAIEditorActionContract API) with a null/empty body, or a JSON payload like {"id":"..."} with no name and no action text; an empty-string Name and Action after client-side trimming.
Common situations: Plugin or script calling the API with a partially built action object; frontend form submitted with all fields blank; JSON unmarshalling producing a zero-value struct.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- provider base URL is required
- AI editor action not found
- AI editor input is empty
- assetPath is required for analyze
- block [ ] type is locked: expected , got
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/c8516b070ebbce4b.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/ai_editor.go:72
func GetAIEditorActions() (ret []*AIEditorAction, err error) {
waitForSyncingStorages()
aiEditorActionsLock.Lock()
defer aiEditorActionsLock.Unlock()
data, err := loadAIEditorActions()
if err != nil {
return nil, err
}
if err = migrateLegacyAIEditorActions(data, !util.ReadOnly); err != nil {
return nil, err
}
return data.Actions, nil
}
func SaveAIEditorAction(action *AIEditorAction) (ret *AIEditorAction, err error) {
if action == nil || (action.Name == "" && action.Action == "") {
return nil, errors.New("AI editor action must not be empty")
}
if action.ID != "" && !ast.IsNodeIDPattern(action.ID) {
return nil, errors.New("invalid AI editor action ID")
}
waitForSyncingStorages()
aiEditorActionsLock.Lock()
defer aiEditorActionsLock.Unlock()
data, err := loadAIEditorActions()
if err != nil {
return nil, err
}
if err = migrateLegacyAIEditorActions(data, true); err != nil {
return nil, err
}
ret = &AIEditorAction{View on GitHub (pinned to 9f775e8a12)