siyuan-note/siyuan · error
save session file failed: %w
Error message
save session file failed: %w
What it means
The actual persistence step of SaveSessionState: filelock.WriteFile atomically writes session.json under the session directory (kernel/agent/session.go:417-418). Any failure is wrapped as 'save session file failed'. The directory already exists at this point, so failures are write-level: disk full, permission on the file itself, or the cross-process file lock being unavailable.
Source
Thrown at kernel/agent/session.go:418
return currentRevision, nil, ErrSessionConflict
}
}
newRevision := currentRevision + 1
newData["revision"] = newRevision
if commitTurnID != "" {
newData["lastCommittedTurnID"] = commitTurnID
}
data, err = gulu.JSON.MarshalIndentJSON(newData, "", "\t")
if err != nil {
return currentRevision, nil, fmt.Errorf("encode session data failed: %w", err)
}
if err := os.MkdirAll(dir, 0755); err != nil {
return currentRevision, nil, fmt.Errorf("create session dir failed: %w", err)
}
if err := filelock.WriteFile(path, data); err != nil {
return currentRevision, nil, fmt.Errorf("save session file failed: %w", err)
}
if commitTurnID != "" {
if err := markRuntimeCommittedLocked(meta.ID, commitTurnID); err != nil {
logging.LogWarnf("commit agent runtime failed: %s", err)
}
}
title, _ := newData["title"].(string)
if title == "" {
title = "AI Agent"
}
createdAt := meta.CreatedAt
if value := numberToInt64(newData["createdAt"]); value > 0 {
createdAt = value
}
updatedAt := meta.UpdatedAt
if value := numberToInt64(newData["updatedAt"]); value > 0 {
updatedAt = valueView on GitHub (pinned to afa823b6b4)
Solutions
- Free disk space / fix ownership of session.json, then re-run the save from a freshly loaded session (revision may have advanced)
- Delete a stale filelock lock file under the workspace if no other kernel instance is running
- On Windows, exclude the workspace from antivirus real-time scanning
- Check kernel logs — a failure here after a successful write of runtime state means the turn commit needs to be redone with the same commitTurnID
Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: confirm space and file writability before long agent turns // df -h <workspace> && test -w <workspace>/data/storage/ai/agent/sessions/<id>/session.json
Type guard
null
Try / catch
catch (e) {
if (/save session file failed/.test(e?.data?.msg ?? '')) {
// fix disk/lock cause; re-GET the session for the latest revision; retry the save once
}
} Prevention
- Monitor free space during long agent sessions
- Release stale filelock locks only when no other kernel instance is running
- Retry saves from a freshly loaded state — revision may have advanced past your copy
When it happens
Trigger: POST /api/ai/agent/saveSession when the disk is full (ENOSPC), session.json is read-only or owned by another user (EACCES), a stale lock file blocks filelock on Windows, or the filesystem is transient (network volume dropped). Note the revision was already computed — the caller must re-load before retrying.
Common situations: Full disk during long agent sessions; antivirus/indexer holding the file on Windows; two SiYuan instances on the same workspace without the sync-detection noticing; flaky removable storage.
Related errors
- read session file failed: %w
- create session dir failed: %w
- invalid frontend capability ID: %s
- frontend capability description is required: %s
- unsupported agent runtime schema version: %d
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/6d80c824428b6b2c.
Report an issue: GitHub.