{"record":{"id":"1d65a2934b7ce1cb","repo":"m1k1o/neko","slug":"unable-to-refresh-file-transfer-list-w","errorCode":null,"errorMessage":"unable to refresh file transfer list: %w","messagePattern":"unable to refresh file transfer list: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/plugins/filetransfer/manager.go","lineNumber":202,"sourceCode":"\n\t\t\t\t\tif changed {\n\t\t\t\t\t\tm.broadcastUpdate()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase err := <-watcher.Errors:\n\t\t\t\tm.logger.Err(err).Msg(\"error in file transfer dir watcher\")\n\t\t\t}\n\t\t}\n\t}()\n\n\tif err := watcher.Add(m.config.RootDir); err != nil {\n\t\treturn fmt.Errorf(\"unable to watch file transfer dir: %w\", err)\n\t}\n\n\t// initial refresh\n\terr, changed := m.refresh()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to refresh file transfer list: %w\", err)\n\t}\n\tif changed {\n\t\tm.broadcastUpdate()\n\t}\n\n\treturn nil\n}\n\nfunc (m *Manager) deleteFileHandler(w http.ResponseWriter, r *http.Request) error {\n\tsession, ok := auth.GetSession(r)\n\tif !ok {\n\t\treturn utils.HttpUnauthorized(\"session not found\")\n\t}\n\n\tenabled, err := m.isEnabledForSession(session)\n\tif err != nil {\n\t\treturn utils.HttpInternalServerError().\n\t\t\tWithInternalErr(err).","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/internal/plugins/filetransfer/manager.go#L184-L220","documentation":"Returned by Manager.Start when the initial m.refresh() of the file-transfer listing fails; refresh scans RootDir and rebuilds the shared file list, and any error there is wrapped with this message. The watcher is already running at this point, so Start aborts after the watcher goroutine was spawned.","triggerScenarios":"Start succeeds creating and registering the watcher, then the first refresh() returns an error — e.g. the RootDir disappeared between watch registration and refresh, listing fails due to permissions, or refresh's internal file-stat/queue operations error out.","commonSituations":"Race where the watched directory is deleted/recreated at startup; RootDir on a flaky network mount; permission changes between watcher.Add (succeeded) and the directory read.","solutions":["Confirm RootDir still exists and is readable by the process at startup; fix permissions or recreate the directory","Retry Start — the wrapped %w error carries the underlying cause; inspect it for the exact failure","Check for startup races (another process wiping/recreating the dir) and pin RootDir to a stable path","If RootDir is on a network mount, ensure it is mounted before the plugin starts (init order / readiness check)"],"exampleFix":"// before (compose)\ncommand: server start  # runs before volume mount completes\n\n// after\nvolumes:\n  - ./filetransfer:/var/filetransfer\ndepends_on:\n  volume-init:\n    condition: service_completed_successfully","handlingStrategy":"retry","validationCode":"if _, err := os.ReadDir(m.config.RootDir); err != nil {\n    return fmt.Errorf(\"root dir not listable before Start: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"var err error\nfor i := 0; i < 3; i++ {\n    if err = m.Start(); err == nil || !strings.Contains(err.Error(), \"unable to refresh file transfer list\") {\n        break\n    }\n    time.Sleep(500 * time.Millisecond) // tolerate transient dir/mount races\n}\nif err != nil { log.Error().Err(err).Msg(\"file transfer refresh failed\") }","preventionTips":["Ensure the volume backing RootDir is mounted before the server starts (init ordering)","Avoid external processes that wipe/recreate RootDir while the server boots","Log refresh failures with the wrapped cause to distinguish permissions vs missing dir"],"tags":["go","filesystem","file-transfer","startup"],"backgroundTag":"directory-listing-failed","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}