{"record":{"id":"c8518aa3702cf95a","repo":"siyuan-note/siyuan","slug":"move-s-to-s-failed-w","errorCode":null,"errorMessage":"move [%s] to [%s] failed: %w","messagePattern":"move \\[(.+?)\\] to \\[(.+?)\\] failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/util/working_mobile.go","lineNumber":204,"sourceCode":"\t\t\treturn false, fmt.Errorf(\"destination [%s] already exists\", to)\n\t\t} else if !errors.Is(statErr, fs.ErrNotExist) {\n\t\t\treturn false, fmt.Errorf(\"stat destination [%s] failed: %w\", to, statErr)\n\t\t}\n\t\tmoves = append(moves, workspaceDirMove{from: from, to: to})\n\t}\n\n\tvar completed []workspaceDirMove\n\tfor _, move := range moves {\n\t\tif renameErr := os.Rename(move.from, move.to); renameErr != nil {\n\t\t\tvar rollbackErrors []error\n\t\t\tfor i := len(completed) - 1; 0 <= i; i-- {\n\t\t\t\tcompletedMove := completed[i]\n\t\t\t\tif rollbackErr := os.Rename(completedMove.to, completedMove.from); rollbackErr != nil {\n\t\t\t\t\trollbackErrors = append(rollbackErrors, fmt.Errorf(\"rollback [%s] to [%s] failed: %w\",\n\t\t\t\t\t\tcompletedMove.to, completedMove.from, rollbackErr))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false, errors.Join(append([]error{fmt.Errorf(\"move [%s] to [%s] failed: %w\", move.from, move.to, renameErr)}, rollbackErrors...)...)\n\t\t}\n\t\tcompleted = append(completed, move)\n\t}\n\n\tfor _, move := range completed {\n\t\tlogging.LogInfof(\"moved legacy iOS workspace dir [from=%s, to=%s]\", move.from, move.to)\n\t}\n\treturn true, nil\n}\n\nfunc replaceLegacyIOSWorkspacePath(workspacePaths []string, workspaceBaseDir, defaultWorkspaceDir string) []string {\n\tfor i, workspacePath := range workspacePaths {\n\t\tif filepath.Clean(workspacePath) == filepath.Clean(workspaceBaseDir) {\n\t\t\tworkspacePaths[i] = defaultWorkspaceDir\n\t\t}\n\t}\n\treturn DeduplicateWorkspacePaths(workspacePaths)\n}","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/working_mobile.go#L186-L222","documentation":"The initial os.Rename of a legacy workspace entry from its old location to <base>/siyuan failed. On failure, migration attempts to rename back all already-completed moves and returns the joined error, so no data loss occurs but the workspace is not migrated.","triggerScenarios":"migrateLegacyIOSWorkspace calls os.Rename(move.from, move.to) and it errors - source vanished, destination created concurrently, EXDEV across filesystems, or permission failure.","commonSituations":"Legacy dir and default dir on different volumes (cross-device rename); another process locking/holding files; disk full; the app killed mid-migration previously leaving inconsistent expectations.","solutions":["Read the wrapped %w error: EXDEV means use copy+delete; ENOENT means re-check which side is missing","Ensure both source and destination live on the same volume/container path","Close other SiYuan instances and retry the migration","Free storage space if ENOSPC, then restart the app to rerun migration (it is idempotent per-entry: missing sources are skipped)","If rollback errors were joined, manually reconcile the directories as described in the log"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Go: pre-flight both endpoints of every move\nfor _, name := range legacyIOSWorkspaceEntries {\n    if _, err := os.Lstat(filepath.Join(base, name)); err != nil { continue }\n    if _, err := os.Lstat(filepath.Join(base, \"siyuan\", name)); err == nil {\n        return fmt.Errorf(\"pre-flight: %s would collide\", name)\n    }\n}","typeGuard":null,"tryCatchPattern":"// Go\nmigrated, err := migrateLegacyIOSWorkspace(base)\nif err != nil {\n    var perr *fs.PathError\n    if errors.As(err, &perr) && errors.Is(perr.Err, syscall.EXDEV) {\n        // fall back to copy+delete migration across filesystems\n        err = migrateByCopy(base)\n    }\n}","preventionTips":["Ensure source and destination are on the same filesystem/volume","Free storage space before first-launch migration","Retry is safe: migration skips entries whose sources no longer exist","Check the joined error list for accompanying rollback failures before retrying"],"tags":["go","filesystem","ios","migration","rename"],"backgroundTag":"file-move-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}