siyuan-note/siyuan · error
copy asset [%s] to [%s] failed: %w
Error message
copy asset [%s] to [%s] failed: %w
What it means
createAssetsHistory (kernel/model/history.go:903-908) fails when filelock.Copy of the asset into the history tree errors with anything other than os.IsNotExist (missing sources are deliberately skipped with continue). The %w preserves the real I/O error: permission denied on source or destination, disk full mid-copy, or a file held with an exclusive lock by another process (typical on Windows).
Source
Thrown at kernel/model/history.go:907
if err != nil {
return fmt.Errorf("get history directory failed: %w", err)
}
for _, file := range assets {
assetRelPath, relErr := filepath.Rel(filepath.Join(util.DataDir, "assets"), file)
if relErr != nil || assetRelPath == "." || strings.HasPrefix(assetRelPath, ".."+string(filepath.Separator)) {
return errors.New("asset path must be under assets")
}
historyPath := filepath.Join(historyDir, "assets", assetRelPath)
if err = os.MkdirAll(filepath.Dir(historyPath), 0755); err != nil {
return fmt.Errorf("create history directory [%s] failed: %w", filepath.Dir(historyPath), err)
}
if err = filelock.Copy(file, historyPath); err != nil {
if os.IsNotExist(err) {
continue
}
return fmt.Errorf("copy asset [%s] to [%s] failed: %w", file, historyPath, err)
}
}
indexHistoryDir(filepath.Base(historyDir), util.NewLute())
return
}
func (box *Box) generateDocHistory0() {
files := box.recentModifiedDocs()
if 1 > len(files) {
return
}
historyDir, err := getHistoryDir(HistoryOpUpdate)
if err != nil {
logging.LogErrorf("get history dir failed: %s", err)
return
}View on GitHub (pinned to afa823b6b4)
Solutions
- Read the wrapped error (errors.Is fs.ErrPermission / fs.ErrNoSpace etc.) and fix that specific condition
- Verify read permission on the source asset and write permission on the history destination
- Free disk space and retry; snapshot generation runs periodically and will succeed once space exists
- On Windows, close or exclude the workspace from programs holding exclusive locks, then retry
Defensive patterns
Strategy: retry
Validate before calling
if fi, err := os.Stat(file); err != nil {
return err
} else if fi.Mode().Perm()&0400 == 0 {
return fmt.Errorf("asset not readable: %s", file)
} Try / catch
var err error
for i := 0; i < 3; i++ {
if err = createAssetsHistory(files); err == nil {
break
}
if !errors.Is(err, fs.ErrPermission) && !errors.Is(err, fs.ErrTemporary) {
break // permanent error, inspect wrapped cause
}
time.Sleep(time.Duration(i+1) * time.Second)
} Prevention
- On Windows, exclude the workspace from AV/sync tools that take exclusive locks
- Keep source assets readable (0644) and history/ writable
- Treat permission and no-space wrapped errors as permanent, locks as transient
When it happens
Trigger: The source asset is unreadable (mode 000, ownership mismatch), the destination history dir became read-only, ENOSPC hits mid-copy of a large media file, or an antivirus/indexer/other program holds the asset open exclusively on Windows.
Common situations: AV scanners or sync clients locking asset files on Windows; Docker volume permission drift; disks filling during snapshots of large video/audio assets.
Related errors
- unsupported agent runtime schema version: %d
- write data [%s] failed: %s
- install skill %s failed: %s
- invalid frontend capability ID: %s
- frontend capability description is required: %s
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/35c88afeb0ccd7c7.
Report an issue: GitHub.