{"record":{"id":"00b3129de0022f79","repo":"siyuan-note/siyuan","slug":"read-workspace-conf-s-failed-s","errorCode":null,"errorMessage":"read workspace conf [%s] failed: %s","messagePattern":"read workspace conf \\[(.+?)\\] failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/working.go","lineNumber":416,"sourceCode":"\ttargetLower := strings.ToLower(target)\n\tvar result []string\n\tfor _, p := range paths {\n\t\tif strings.ToLower(p) == targetLower {\n\t\t\tcontinue\n\t\t}\n\t\tresult = append(result, p)\n\t}\n\treturn result\n}\n\nfunc ReadWorkspacePaths() (ret []string, err error) {\n\tret = []string{}\n\tworkspaceConf := filepath.Join(HomeDir, \".config\", \"siyuan\", \"workspace.json\")\n\tdata, err := os.ReadFile(workspaceConf)\n\tif err != nil {\n\t\tmsg := fmt.Sprintf(\"read workspace conf [%s] failed: %s\", workspaceConf, err)\n\t\tlogging.LogError(msg)\n\t\terr = errors.New(msg)\n\t\treturn\n\t}\n\n\tif err = gulu.JSON.UnmarshalJSON(data, &ret); err != nil {\n\t\tmsg := fmt.Sprintf(\"unmarshal workspace conf [%s] failed: %s\", workspaceConf, err)\n\t\tlogging.LogError(msg)\n\t\terr = errors.New(msg)\n\t\treturn\n\t}\n\n\tvar tmp []string\n\tworkspaceBaseDir := filepath.Dir(HomeDir)\n\tfor _, d := range ret {\n\t\tif ContainerIOS == Container && strings.Contains(d, \"/Documents/\") {\n\t\t\t// iOS 端沙箱路径会变化，需要转换为相对路径再拼接当前沙箱中的工作空间基路径\n\t\t\td = d[strings.Index(d, \"/Documents/\")+len(\"/Documents/\"):]\n\t\t\td = filepath.Join(workspaceBaseDir, d)\n\t\t}","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/util/working.go#L398-L434","documentation":"ReadWorkspacePaths reads the global workspace registry at ~/.config/siyuan/workspace.json (a JSON array of workspace directory paths). If the file cannot be read at all (missing, permission denied, is a directory), it logs and returns 'read workspace conf [%s] failed: %s'. All workspace operations (open, create, remove, list) depend on this call.","triggerScenarios":"Any caller (getWorkspaces, setWorkspaceDir, createWorkspaceDir, removeWorkspaceDir, removeWorkspaceDirPhysically) invoking ReadWorkspacePaths when os.ReadFile(~/.config/siyuan/workspace.json) fails — typically the file doesn't exist yet on first run, or its permissions/ownership prevent reading, or the path is a directory.","commonSituations":"First launch before workspace.json was ever created; config directory owned by another user after sudo-installed kernel; roaming-profile/backup tools replacing the file with a directory; disk errors.","solutions":["Check that ~/.config/siyuan/workspace.json exists; on a fresh install create it as an empty JSON array: []","Fix file permissions so the kernel user can read it (chmod/chown)","If the path is a directory or corrupted beyond repair, back it up and replace it with []","Verify the HomeDir resolution matches expectations when running under a service account"],"exampleFix":"# before\nls -l ~/.config/siyuan/workspace.json  # permission denied\n# after\nsudo chown $USER ~/.config/siyuan/workspace.json\nchmod 600 ~/.config/siyuan/workspace.json\n# or on first run:\necho '[]' > ~/.config/siyuan/workspace.json","handlingStrategy":"validation","validationCode":"workspaceConf := filepath.Join(home, \".config\", \"siyuan\", \"workspace.json\")\nif info, err := os.Stat(workspaceConf); os.IsNotExist(err) {\n    os.MkdirAll(filepath.Dir(workspaceConf), 0755)\n    os.WriteFile(workspaceConf, []byte(\"[]\"), 0644) // bootstrap empty registry\n} else if err == nil && info.IsDir() {\n    return fmt.Errorf(\"%s is a directory\", workspaceConf)\n}","typeGuard":null,"tryCatchPattern":"paths, err := util.ReadWorkspacePaths()\nif err != nil {\n    if strings.Contains(err.Error(), \"read workspace conf\") {\n        // first run or unreadable conf: bootstrap with empty list\n        os.WriteFile(confPath, []byte(\"[]\"), 0644)\n        paths, err = util.ReadWorkspacePaths()\n    }\n    if err != nil { return err }\n}","preventionTips":["Ensure the kernel user owns ~/.config/siyuan and its files","Bootstrap workspace.json to [] on first run instead of leaving it absent","Never let backup/roaming tools replace the file with a directory","Check HomeDir resolution when running as a service account"],"tags":["filesystem","config","workspace"],"backgroundTag":"file-read-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"}