siyuan-note/siyuan · error

invalid AI editor action data

Error message

invalid AI editor action data

What it means

After parsing, loadAIEditorActions (kernel/model/ai_editor.go:175) sanity-checks every entry: it must be non-nil, its ID must match the node-ID pattern, and it must have a name or an action prompt. Any violation returns this generic data error — the file parses as JSON and has the right version, but its contents were not produced by the kernel.

Source

Thrown at kernel/model/ai_editor.go:175

	data, err := filelock.ReadFile(dataPath)
	if err != nil {
		return nil, fmt.Errorf("read AI editor actions failed: %w", err)
	}
	if err = gulu.JSON.UnmarshalJSON(data, ret); err != nil {
		return nil, fmt.Errorf("unmarshal AI editor actions failed: %w", err)
	}
	if ret.Version != aiEditorActionsVersion {
		return nil, fmt.Errorf("unsupported AI editor actions version [%d]", ret.Version)
	}
	if ret.Actions == nil {
		ret.Actions = []*AIEditorAction{}
	}

	ids := make(map[string]struct{}, len(ret.Actions))
	for _, action := range ret.Actions {
		if action == nil || !ast.IsNodeIDPattern(action.ID) || (action.Name == "" && action.Action == "") {
			return nil, errors.New("invalid AI editor action data")
		}
		if _, ok := ids[action.ID]; ok {
			return nil, fmt.Errorf("duplicate AI editor action ID [%s]", action.ID)
		}
		ids[action.ID] = struct{}{}
	}
	return ret, nil
}

func saveAIEditorActions(data *aiEditorActionsData) (err error) {
	data.Version = aiEditorActionsVersion
	if data.Actions == nil {
		data.Actions = []*AIEditorAction{}
	}

	dirPath := filepath.Dir(aiEditorActionsPath())
	if err = os.MkdirAll(dirPath, 0755); err != nil {
		return fmt.Errorf("create AI editor actions directory failed: %w", err)

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Open actions.json and fix each entry to the kernel shape: {"id":"<14-digit-time>-<7-char-suffix>","name":"...","action":"..."} with at least one of name/action non-empty
  2. Give hand-added entries a correctly shaped unique ID, e.g. timestamp-based 20240101120000-a1b2c3d that no other entry uses
  3. Or delete/rename the file — defaults are regenerated and legacy actions re-imported from localStorage

Example fix

// before: {"version":1,"actions":[{"name":"Translate"}]}
// after:  {"version":1,"actions":[{"id":"20240101120000-a1b2c3d","name":"Translate","action":"Translate to English:\n{content}"}]}
Defensive patterns

Strategy: try-catch

Validate before calling

var nodeIDPattern = regexp.MustCompile(`^[0-9]{14}-[a-z0-9]{7}$`)

func validEntries(actions []*AIEditorAction) bool {
    for _, a := range actions {
        if a == nil || !nodeIDPattern.MatchString(a.ID) || (a.Name == "" && a.Action == "") {
            return false
        }
    }
    return true
}

Type guard

function isWellFormedAction(a: any): boolean {
    return (
        !!a &&
        typeof a.id === "string" && /^[0-9]{14}-[a-z0-9]{7}$/.test(a.id) &&
        (typeof a.name === "string" || typeof a.action === "string") &&
        ((a.name ?? "") !== "" || (a.action ?? "") !== "")
    );
}

Try / catch

if err != nil && err.Error() == "invalid AI editor action data" {
    // inspect actions.json entries one by one; fix shape or reset the file
    backupAndResetActionsFile()
    return
}

Prevention

When it happens

Trigger: actions.json entries like null in the actions array, {"name":"x"} with no id, an id like "foo", or an entry with both name and action empty. Typically follows a hand edit or a bad merge from a sync tool rather than kernel writes, which always assign valid IDs.

Common situations: Hand-crafted action files missing the id field (the server always writes one); a JSON merge that dropped fields; copy-pasting an action between files without the id; nulls introduced by script-generated files.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/28fcf38c71f5ba77. Report an issue: GitHub.