siyuan-note/siyuan · error

unsupported AI editor actions version [%d]

Error message

unsupported AI editor actions version [%d]

What it means

loadAIEditorActions enforces that the file's version field equals aiEditorActionsVersion (1). If the stored JSON declares any other version (older or newer), the loader refuses to proceed rather than guess at the schema. This is a forward/backward compatibility guard for the on-disk format.

Source

Thrown at kernel/model/ai_editor.go:166

func loadAIEditorActions() (ret *aiEditorActionsData, err error) {
	ret = &aiEditorActionsData{
		Version: aiEditorActionsVersion,
		Actions: []*AIEditorAction{},
	}
	dataPath := aiEditorActionsPath()
	if !filelock.IsExist(dataPath) {
		return ret, nil
	}

	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
}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check the reported version against the supported value (1 in this codebase); do not hand-edit it to 1 blindly — confirm the schema also matches v1
  2. If the file was written by a newer build, upgrade SiYuan to that build instead of downgrading the data
  3. If the version was tampered with and the actions array matches the v1 schema, restore version to 1 in the file (keep a backup first)
  4. Restore the file from sync history or backup if it originated from an incompatible source

Example fix

// before: version edited away from the supported value
{"version":99,"actions":[...]}
// after
{"version":1,"actions":[...]}
Defensive patterns

Strategy: validation

Validate before calling

raw, _ := os.ReadFile("data/storage/ai/editor/actions.json")
var probe struct{ Version int `json:"version"` }
if err := json.Unmarshal(raw, &probe); err == nil && probe.Version != 1 {
    return fmt.Errorf("unsupported actions.json version %d; upgrade SiYuan", probe.Version)
}

Try / catch

actions, err := GetAIEditorActions()
if err != nil && strings.Contains(err.Error(), "unsupported AI editor actions version") {
    return fmt.Errorf("data written by an incompatible SiYuan version; upgrade the kernel: %w", err)
}

Prevention

When it happens

Trigger: GetAIEditorActions, SaveAIEditorAction, or RemoveAIEditorAction loads an actions.json whose version field was edited to another integer, or the file was written by a different (future or past) build with an incompatible version constant.

Common situations: The user hand-edited the file and changed the version number; the file was produced by a newer development build of the kernel and then opened by an older release; a sync brought a file from a machine running a different version.

Related errors


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