{"record":{"id":"c31caf55e3693402","repo":"siyuan-note/siyuan","slug":"read-ai-editor-actions-failed-w","errorCode":null,"errorMessage":"read AI editor actions failed: %w","messagePattern":"read AI editor actions failed: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/ai_editor.go","lineNumber":160,"sourceCode":"}\n\nfunc aiEditorActionsPath() string {\n\treturn filepath.Join(util.DataDir, \"storage\", \"ai\", \"editor\", \"actions.json\")\n}\n\nfunc loadAIEditorActions() (ret *aiEditorActionsData, err error) {\n\tret = &aiEditorActionsData{\n\t\tVersion: aiEditorActionsVersion,\n\t\tActions: []*AIEditorAction{},\n\t}\n\tdataPath := aiEditorActionsPath()\n\tif !filelock.IsExist(dataPath) {\n\t\treturn ret, nil\n\t}\n\n\tdata, err := filelock.ReadFile(dataPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read AI editor actions failed: %w\", err)\n\t}\n\tif err = gulu.JSON.UnmarshalJSON(data, ret); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal AI editor actions failed: %w\", err)\n\t}\n\tif ret.Version != aiEditorActionsVersion {\n\t\treturn nil, fmt.Errorf(\"unsupported AI editor actions version [%d]\", ret.Version)\n\t}\n\tif ret.Actions == nil {\n\t\tret.Actions = []*AIEditorAction{}\n\t}\n\n\tids := make(map[string]struct{}, len(ret.Actions))\n\tfor _, action := range ret.Actions {\n\t\tif action == nil || !ast.IsNodeIDPattern(action.ID) || (action.Name == \"\" && action.Action == \"\") {\n\t\t\treturn nil, errors.New(\"invalid AI editor action data\")\n\t\t}\n\t\tif _, ok := ids[action.ID]; ok {\n\t\t\treturn nil, fmt.Errorf(\"duplicate AI editor action ID [%s]\", action.ID)","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/ai_editor.go#L142-L178","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"path := filepath.Join(util.DataDir, \"storage\", \"ai\", \"editor\", \"actions.json\")\nif info, err := os.Stat(path); err == nil {\n    if info.Mode().Perm()&0400 == 0 {\n        return fmt.Errorf(\"actions file not readable; fix permissions on %s\", path)\n    }\n}","typeGuard":null,"tryCatchPattern":"actions, err := model.GetAIEditorActions()\nif err != nil && strings.HasPrefix(err.Error(), \"read AI editor actions failed\") {\n    // environment problem: check perms/mount/disk, then retry after fixing\n    reportFileSystemIssue(err)\n    return\n}","preventionTips":["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"],"tags":["ai","filesystem","permissions","io-error"],"backgroundTag":"file-read-permission-denied","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}