siyuan-note/siyuan · error
unmarshal AI editor actions failed: %w
Error message
unmarshal AI editor actions failed: %w
What it means
loadAIEditorActions (kernel/model/ai_editor.go:163) unmarshals the contents of <workspace>/data/storage/ai/editor/actions.json with gulu.JSON.UnmarshalJSON. If the bytes are not valid JSON, the parse error is wrapped with this message. The file is machine-written, so corruption almost always means an external edit or an interrupted write.
Source
Thrown at kernel/model/ai_editor.go:163
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)
}
ids[action.ID] = struct{}{}
}View on GitHub (pinned to afa823b6b4)
Solutions
- Open <workspace>/data/storage/ai/editor/actions.json in an editor and run a JSON validator; fix the syntax error keeping the {"version":1,"actions":[...]} shape
- If unfixable, rename/delete the file — the kernel recreates defaults and migrates legacy actions from the localStorage key "local-ai"
- Prevent recurrence: never edit while SiYuan is running, and avoid two instances sharing one workspace
- Restore from a workspace backup/snapshot if the actions are precious
Example fix
// before: actions.json contains {"version":1,"actions":[{"id":"20240101120000-a1b2c3d","name":"Translate",]}
// after: {"version":1,"actions":[{"id":"20240101120000-a1b2c3d","name":"Translate"}]} Defensive patterns
Strategy: try-catch
Validate before calling
data, err := os.ReadFile(path)
if err == nil {
if json.Valid(data) {
_ = json.Unmarshal(data, &aiEditorActionsData{}) // dry-run parse
} else {
return errors.New("actions.json is corrupt; restore or delete it")
}
} Try / catch
actions, err := model.GetAIEditorActions()
if err != nil && strings.HasPrefix(err.Error(), "unmarshal AI editor actions failed") {
backupAndResetActionsFile() // rename file; kernel regenerates + re-imports legacy 'local-ai'
actions, err = model.GetAIEditorActions()
} Prevention
- Never hand-edit actions.json while the kernel is running
- Run one SiYuan instance per workspace; concurrent sync tools corrupt JSON stores
- Keep the disk from filling — truncated writes are a classic corruption source
When it happens
Trigger: actions.json was hand-edited and now has a trailing comma, unquoted key, or was truncated; a crash or power loss left a partial file; the file was replaced by merge-conflict output from a sync tool (<<<<<<< markers); encoding damage (BOM/cut multi-byte char).
Common situations: Users hand-tuning actions in a text editor; two SiYuan instances or a sync tool (WebDAV/cloud drive) racing on the same workspace; file truncated by a full disk during save.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- parse json [%s] to tree failed: %w
- invalid AI editor action data
- duplicate AI editor action ID [%s]
- read AI editor actions failed: %w
- create AI editor actions directory failed: %w
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/ec10af8557645e5b.
Report an issue: GitHub.