siyuan-note/siyuan · error
create AI editor actions directory failed: %w
Error message
create AI editor actions directory failed: %w
What it means
saveAIEditorActions (kernel/model/ai_editor.go:193) first ensures the storage directory <workspace>/data/storage/ai/editor exists via os.MkdirAll(0755) before writing actions.json. If directory creation fails, the raw OS error is wrapped with this message and the save (create, update, or delete of any AI editor action) is aborted. It is purely an environment/permissions failure.
Source
Thrown at kernel/model/ai_editor.go:193
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)
}
bytes, err := gulu.JSON.MarshalIndentJSON(data, "", " ")
if err != nil {
return fmt.Errorf("marshal AI editor actions failed: %w", err)
}
if err = filelock.WriteFile(aiEditorActionsPath(), bytes); err != nil {
return fmt.Errorf("write AI editor actions failed: %w", err)
}
return nil
}
func migrateLegacyAIEditorActions(data *aiEditorActionsData, persist bool) (err error) {
localStorage := GetLocalStorage()
legacyRaw, ok := localStorage[legacyAIEditorActionsStorageKey]
if !ok {
return nil
}
View on GitHub (pinned to afa823b6b4)
Solutions
- Check that the SiYuan process can create dirs under <workspace>/data/storage (fix ownership/modes with chown/chmod)
- Remove any regular file occupying the ai/editor path components so directories can be created
- Verify the workspace volume is mounted read-write and has free space
- If the workspace is intentionally read-only, stop trying to save actions — ReadOnly mode cannot persist them
Defensive patterns
Strategy: try-catch
Validate before calling
dir := filepath.Join(util.DataDir, "storage", "ai", "editor")
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("workspace not writable at %s: %w", dir, err)
}
// only then call SaveAIEditorAction / RemoveAIEditorAction Try / catch
_, err := model.SaveAIEditorAction(action)
if err != nil && strings.HasPrefix(err.Error(), "create AI editor actions directory failed") {
// fix ownership/modes on <workspace>/data/storage or remount read-write, then retry
reportWorkspaceNotWritable(err)
return
} Prevention
- Verify workspace write access after restoring from archives or moving between machines
- Keep path components data/, storage/, ai/ as directories — a stray file named 'ai' or 'editor' blocks creation
- In read-only deployments, do not expose action-saving UI
When it happens
Trigger: MkdirAll fails on: permission denied somewhere along data/storage/ai/editor, a read-only filesystem, a path component that exists as a regular file (e.g. a file named 'ai' or 'editor'), or a full/broken disk. Also occurs when the kernel runs in ReadOnly mode against a locked-down workspace.
Common situations: Workspace restored from an archive that lost directory permissions or changed ownership; workspace on a read-only mount or a drive removed mid-session; a stray file named 'editor' or 'ai' blocking the path; sandboxed/containerized kernels without write access to the data dir.
Related errors
- read AI editor actions 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/0c1b3457c7cb1d42.
Report an issue: GitHub.