{"record":{"id":"0714deec81fb2fff","repo":"siyuan-note/siyuan","slug":"read-destination-s-failed-w","errorCode":null,"errorMessage":"read destination [%s] failed: %w","messagePattern":"read destination \\[(.+?)\\] failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/working_mobile.go","lineNumber":168,"sourceCode":"\tfrom string\n\tto   string\n}\n\nfunc migrateLegacyIOSWorkspace(workspaceBaseDir string) (migrated bool, err error) {\n\tif ContainerIOS != Container || !gulu.File.IsDir(workspaceBaseDir) {\n\t\treturn false, nil\n\t}\n\n\tfor _, name := range []string{\"conf\", \"data\", \"temp\"} {\n\t\tif !gulu.File.IsDir(filepath.Join(workspaceBaseDir, name)) {\n\t\t\treturn false, nil\n\t\t}\n\t}\n\n\tdefaultWorkspaceDir := filepath.Join(workspaceBaseDir, \"siyuan\")\n\tdestinationEntries, readErr := os.ReadDir(defaultWorkspaceDir)\n\tif readErr != nil {\n\t\treturn false, fmt.Errorf(\"read destination [%s] failed: %w\", defaultWorkspaceDir, readErr)\n\t}\n\tif 0 < len(destinationEntries) {\n\t\treturn false, fmt.Errorf(\"destination [%s] is not empty\", defaultWorkspaceDir)\n\t}\n\n\tvar moves []workspaceDirMove\n\tfor _, name := range legacyIOSWorkspaceEntries {\n\t\tfrom := filepath.Join(workspaceBaseDir, name)\n\t\tif _, statErr := os.Lstat(from); statErr != nil {\n\t\t\tif errors.Is(statErr, fs.ErrNotExist) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn false, fmt.Errorf(\"stat source [%s] failed: %w\", from, statErr)\n\t\t}\n\n\t\tto := filepath.Join(defaultWorkspaceDir, name)\n\t\tif _, statErr := os.Lstat(to); statErr == nil {\n\t\t\treturn false, fmt.Errorf(\"destination [%s] already exists\", to)","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/working_mobile.go#L150-L186","documentation":"migrateLegacyIOSWorkspace moves legacy iOS workspace entries into the default workspace dir <base>/siyuan. Before moving, it lists the destination with os.ReadDir; this error wraps any such failure, including the destination not existing or being unreadable. The migration aborts without touching source data.","triggerScenarios":"initWorkspaceDirMobile triggers migration when <workspaceBaseDir>/siyuan cannot be ReadDir: missing directory, permission denied, or path is a file.","commonSituations":"Fresh iOS/HarmonyOS install where <base>/siyuan has not been created yet; sandbox permission changes after an OS upgrade; a stray file named 'siyuan' in the container's documents dir.","solutions":["Ensure the default workspace dir <workspaceBaseDir>/siyuan is created before invoking migration (create it with os.MkdirAll when it does not exist)","Check the wrapped %w error: fs.ErrNotExist means create the dir first; permission errors mean fix container/sandbox permissions","If the path exists but is a file, remove or rename it manually and reinstall/restart","Re-run the app; migration is skipped safely once the destination is readable and empty or already migrated"],"exampleFix":"// before\nif _, err := os.Stat(defaultWorkspaceDir); os.IsNotExist(err) {\n    if err := os.MkdirAll(defaultWorkspaceDir, 0755); err != nil { return false, err }\n}\n// after: ReadDir succeeds and migration proceeds\n// (guard migrateLegacyIOSWorkspace so a not-exist destination creates the dir instead of erroring)","handlingStrategy":"try-catch","validationCode":"// Go: pre-check the destination before migration\nbase := workspaceBaseDir\ndest := filepath.Join(base, \"siyuan\")\nif _, err := os.ReadDir(dest); err != nil {\n    if os.IsNotExist(err) { os.MkdirAll(dest, 0755) } // create so ReadDir succeeds\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, fs.ErrNotExist) {\n        os.MkdirAll(filepath.Join(base, \"siyuan\"), 0755)\n        migrated, err = migrateLegacyIOSWorkspace(base) // retry once\n    }\n}","preventionTips":["Always create the default workspace directory before attempting migration","Trigger migration before first workspace initialization so the destination is empty","Check the wrapped fs.PathError to distinguish not-exist vs permission causes"],"tags":["go","filesystem","ios","migration","directory-read"],"backgroundTag":"directory-not-found","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"}