siyuan-note/siyuan · error
stat source [%s] failed: %w
Error message
stat source [%s] failed: %w
What it means
While enumerating legacy iOS workspace entries to move, os.Lstat on a source entry failed with an error other than fs.ErrNotExist. Migration aborts because it cannot determine whether the source exists, avoiding destructive assumptions about user data.
Source
Thrown at kernel/util/working_mobile.go:181
}
defaultWorkspaceDir := filepath.Join(workspaceBaseDir, "siyuan")
destinationEntries, readErr := os.ReadDir(defaultWorkspaceDir)
if readErr != nil {
return false, fmt.Errorf("read destination [%s] failed: %w", defaultWorkspaceDir, readErr)
}
if 0 < len(destinationEntries) {
return false, fmt.Errorf("destination [%s] is not empty", defaultWorkspaceDir)
}
var moves []workspaceDirMove
for _, name := range legacyIOSWorkspaceEntries {
from := filepath.Join(workspaceBaseDir, name)
if _, statErr := os.Lstat(from); statErr != nil {
if errors.Is(statErr, fs.ErrNotExist) {
continue
}
return false, fmt.Errorf("stat source [%s] failed: %w", from, statErr)
}
to := filepath.Join(defaultWorkspaceDir, name)
if _, statErr := os.Lstat(to); statErr == nil {
return false, fmt.Errorf("destination [%s] already exists", to)
} else if !errors.Is(statErr, fs.ErrNotExist) {
return false, fmt.Errorf("stat destination [%s] failed: %w", to, statErr)
}
moves = append(moves, workspaceDirMove{from: from, to: to})
}
var completed []workspaceDirMove
for _, move := range moves {
if renameErr := os.Rename(move.from, move.to); renameErr != nil {
var rollbackErrors []error
for i := len(completed) - 1; 0 <= i; i-- {
completedMove := completed[i]
if rollbackErr := os.Rename(completedMove.to, completedMove.from); rollbackErr != nil {View on GitHub (pinned to 8641553a1f)
Solutions
- Read the wrapped %w error to identify the syscall failure (permission vs I/O)
- Fix container permissions: reinstall the app or reset its sandbox/documents permissions in system settings
- For offloaded iCloud files, download them locally so Lstat/stat can access them
- Retry after rebooting the device if it is a transient I/O error
Defensive patterns
Strategy: try-catch
Validate before calling
// Go: probe access to the legacy directory before migrating
if _, err := os.ReadDir(workspaceBaseDir); err != nil {
return fmt.Errorf("legacy base dir not readable: %w", err)
} Try / catch
// Go
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && !errors.Is(perr.Err, fs.ErrNotExist) {
// permission or I/O problem: back off, keep legacy data untouched, surface to user
return err
}
} Prevention
- Keep legacy workspace entries on local storage (avoid iCloud offloading) before migration
- Reset app container permissions after OS upgrades if document access is denied
- Never modify permissions of legacy dirs while the app is running
When it happens
Trigger: migrateLegacyIOSWorkspace calls os.Lstat(<workspaceBaseDir>/<name>) and gets a non-ENOENT error (e.g. EACCES, EIO, or a broken symlink edge).
Common situations: Sandbox tightened read permissions on the app container after an OS update; iCloud/offloaded storage making the file inaccessible; filesystem I/O errors on the device.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- stat destination [%s] failed: %w
- read destination [%s] failed: %w
- destination [%s] is not empty
- destination [%s] already exists
- rollback [%s] to [%s] failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/075febb6165065f0.
Report an issue: GitHub.