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

  1. Omit the ID field when creating a new action so the backend generates a valid one
  2. Only pass back IDs previously returned by the backend (valid 20-char node IDs)
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/4ba4e18055013639. Report an issue: GitHub.