siyuan-note/siyuan · error
invalid AI editor action ID
Error message
invalid AI editor action ID
What it means
When updating an existing AI editor action, the ID must match the SiYuan node-ID pattern validated by ast.IsNodeIDPattern. A non-empty ID that fails this pattern is rejected before touching storage, protecting stored action records from malformed identifiers.
Source
Thrown at kernel/model/ai_editor.go:75
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{
ID: action.ID,
Name: action.Name,
Action: action.Action,View on GitHub (pinned to 8641553a1f)
Solutions
- Omit the ID field when creating a new action so the backend generates a valid one
- Only pass back IDs previously returned by the backend (valid 20-char node IDs)
- Fix corrupted stored actions by removing and recreating them
Example fix
// before
await fetchPost('/api/ai/saveAIEditorAction', {id: 'my-action-1', name: 'Summarize', action: '...'})
// after
await fetchPost('/api/ai/saveAIEditorAction', {name: 'Summarize', action: '...'}) // let backend assign ID Defensive patterns
Strategy: validation
Validate before calling
const isNodeID = id => typeof id === 'string' && /^[0-9]{20}-[a-z0-9]{7}$/.test(id); if (a.id && !isNodeID(a.id)) throw new Error('invalid id') Type guard
const isValidActionID = (id) => id === '' || (typeof id === 'string' && /^[0-9]{14}-[a-z0-9]{7}$/.test(id)) Try / catch
try { await saveAction(a) } catch (e) { if (e.message.includes('invalid AI editor action ID')) { delete a.id; await saveAction(a) } } Prevention
- Never fabricate IDs client-side; omit id for new actions
- Echo back only server-issued IDs
- Sanitize imported/stored action configs
When it happens
Trigger: Calling SaveAIEditorAction with an action whose ID is non-empty but not a valid node ID (e.g. random string, URL-safe slug, or truncated ID).
Common situations: Client generating its own IDs instead of letting the backend assign them; corrupted local storage returning malformed IDs; hand-edited action config.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- invalid AI editor action data
- duplicate AI editor action ID [%s]
- invalid frontend capability ID: %s
- AI editor action must not be empty
- invalid appearance ID
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/4ba4e18055013639.
Report an issue: GitHub.