{"record":{"id":"84768d34f58d827b","repo":"siyuan-note/siyuan","slug":"write-ai-editor-actions-failed-w","errorCode":null,"errorMessage":"write AI editor actions failed: %w","messagePattern":"write AI editor actions failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/ai_editor.go","lineNumber":200,"sourceCode":"\treturn ret, nil\n}\n\nfunc saveAIEditorActions(data *aiEditorActionsData) (err error) {\n\tdata.Version = aiEditorActionsVersion\n\tif data.Actions == nil {\n\t\tdata.Actions = []*AIEditorAction{}\n\t}\n\n\tdirPath := filepath.Dir(aiEditorActionsPath())\n\tif err = os.MkdirAll(dirPath, 0755); err != nil {\n\t\treturn fmt.Errorf(\"create AI editor actions directory failed: %w\", err)\n\t}\n\tbytes, err := gulu.JSON.MarshalIndentJSON(data, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"marshal AI editor actions failed: %w\", err)\n\t}\n\tif err = filelock.WriteFile(aiEditorActionsPath(), bytes); err != nil {\n\t\treturn fmt.Errorf(\"write AI editor actions failed: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc migrateLegacyAIEditorActions(data *aiEditorActionsData, persist bool) (err error) {\n\tlocalStorage := GetLocalStorage()\n\tlegacyRaw, ok := localStorage[legacyAIEditorActionsStorageKey]\n\tif !ok {\n\t\treturn nil\n\t}\n\n\tvar legacyActions []*legacyAIEditorAction\n\tif legacyJSON, isString := legacyRaw.(string); isString {\n\t\tif err = gulu.JSON.UnmarshalJSON([]byte(legacyJSON), &legacyActions); err != nil {\n\t\t\treturn fmt.Errorf(\"unmarshal legacy AI editor actions failed: %w\", err)\n\t\t}\n\t} else {\n\t\tlegacyJSON, marshalErr := gulu.JSON.MarshalJSON(legacyRaw)","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/ai_editor.go#L182-L218","documentation":"saveAIEditorActions writes the marshaled JSON via filelock.WriteFile to data/storage/ai/editor/actions.json; a failure there is wrapped with this message. The directory was created successfully, so the failure is at the file level: permissions, disk full, lock contention, or an I/O error while replacing the file.","triggerScenarios":"SaveAIEditorAction, RemoveAIEditorAction, or migrateLegacyAIEditorActions persists the store and filelock.WriteFile fails: actions.json exists but is not writable, the lock file cannot be acquired, the volume is full or read-only, or an EIO occurs mid-write.","commonSituations":"Disk quota or space exhausted on the workspace volume; the file is owned by another user (e.g. created earlier under sudo/root); a second SiYuan instance or backup tool holds the lock; the workspace lives on a removable/network drive that dropped mid-write; antivirus interference on Windows.","solutions":["Check the wrapped OS error and act accordingly: ENOSPC → free space; EACCES → fix permissions/ownership on data/storage/ai/editor/actions.json","Ensure only one SiYuan instance uses this workspace and exclude the data directory from backup/AV file locking","Verify the storage volume is mounted, writable, and not read-only","Retry the save after transient conditions clear; if the file is locked persistently, find and close the holder (lsof/handle.exe)"],"exampleFix":"// before: file owned by root, kernel runs as user\n-rw-r--r-- 1 root root actions.json\n// after\nsudo chown siyuan:siyuan actions.json && sudo chmod 644 actions.json","handlingStrategy":"retry","validationCode":"// ensure target file is writable before saving\np := \"data/storage/ai/editor/actions.json\"\nif f, err := os.OpenFile(p, os.O_WRONLY, 0644); err != nil {\n    return fmt.Errorf(\"actions.json not writable: %w\", err)\n} else { f.Close() }","typeGuard":null,"tryCatchPattern":"err := SaveAIEditorAction(act)\nif err != nil && strings.Contains(err.Error(), \"write AI editor actions failed\") {\n    time.Sleep(200 * time.Millisecond)\n    err = SaveAIEditorAction(act) // retry once for transient lock/IO issues\n}","preventionTips":["Run a single SiYuan instance per workspace to avoid file-lock contention","Keep free headroom on the workspace disk","Exclude data/storage from AV/backup exclusive locks","Do not force-kill the kernel mid-save"],"tags":["filesystem","io","file-lock","write","ai-editor"],"backgroundTag":"file-write-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}