siyuan-note/siyuan · error
read AI editor actions failed: %w
Error message
read AI editor actions failed: %w
What it means
loadAIEditorActions (kernel/model/ai_editor.go:160) reads the persisted actions file at <workspace>/data/storage/ai/editor/actions.json through filelock.ReadFile. If the OS-level read fails (the file exists per filelock.IsExist but cannot be read), the raw error is wrapped with this message and every AI-editor-action API call aborts. This is an environment problem, not a data-format problem.
Source
Thrown at kernel/model/ai_editor.go:160
}
func aiEditorActionsPath() string {
return filepath.Join(util.DataDir, "storage", "ai", "editor", "actions.json")
}
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)View on GitHub (pinned to afa823b6b4)
Solutions
- Check permissions and ownership of <workspace>/data/storage/ai/editor/actions.json and its parent directories (chmod/chown so the SiYuan process can read)
- Verify the workspace filesystem is mounted read-write and healthy (dmesg/Event Viewer for disk errors)
- Close other processes holding the file (sync clients, editors, antivirus) and retry
- As a last resort, move actions.json aside — the kernel regenerates defaults and re-imports legacy actions from localStorage
Defensive patterns
Strategy: try-catch
Validate before calling
path := filepath.Join(util.DataDir, "storage", "ai", "editor", "actions.json")
if info, err := os.Stat(path); err == nil {
if info.Mode().Perm()&0400 == 0 {
return fmt.Errorf("actions file not readable; fix permissions on %s", path)
}
} Try / catch
actions, err := model.GetAIEditorActions()
if err != nil && strings.HasPrefix(err.Error(), "read AI editor actions failed") {
// environment problem: check perms/mount/disk, then retry after fixing
reportFileSystemIssue(err)
return
} Prevention
- Keep workspace ownership stable across moves and restores
- Avoid placing the workspace on flaky network mounts
- Do not lock actions.json with external tools while SiYuan runs
When it happens
Trigger: The actions.json file exists but read(2) fails: permission denied (file or directory mode/ownership), an unreadable network/mount filesystem, the file held by another process with exclusive access, or a disk I/O error surfaced by the kernel.
Common situations: Workspace moved between users so storage/ is owned by another UID; workspace on a failing or unmounted drive; antivirus/backup tools locking the file on Windows; read-only mount after an OS update.
Related errors
- create AI editor actions directory failed: %w
- invalid frontend capability ID: %s
- unsupported agent runtime schema version: %d
- read session file failed: %w
- write data [%s] failed: %s
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/c31caf55e3693402.
Report an issue: GitHub.