{"record":{"id":"3fdb2b681295b2c0","repo":"router-for-me/CLIProxyAPI","slug":"auth-directory-is-unavailable","errorCode":null,"errorMessage":"auth directory is unavailable","messagePattern":"auth directory is unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/pluginhost/auth_callbacks.go","lineNumber":156,"sourceCode":"\t\tauths := manager.List()\n\t\tentries := make([]pluginapi.HostAuthFileEntry, 0, len(auths))\n\t\tfor _, auth := range auths {\n\t\t\tif entry := h.buildHostAuthFileEntry(auth); entry != nil {\n\t\t\t\tentries = append(entries, *entry)\n\t\t\t}\n\t\t}\n\t\tsort.Slice(entries, func(i, j int) bool {\n\t\t\treturn strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name)\n\t\t})\n\t\treturn entries, nil\n\t}\n\treturn h.listAuthFilesFromDisk()\n}\n\nfunc (h *Host) listAuthFilesFromDisk() ([]pluginapi.HostAuthFileEntry, error) {\n\tauthDir := h.resolvedAuthDir()\n\tif authDir == \"\" {\n\t\treturn nil, fmt.Errorf(\"auth directory is unavailable\")\n\t}\n\tentries, errReadDir := os.ReadDir(authDir)\n\tif errReadDir != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read auth dir: %w\", errReadDir)\n\t}\n\tfiles := make([]pluginapi.HostAuthFileEntry, 0)\n\tfor _, entry := range entries {\n\t\tif entry.IsDir() {\n\t\t\tcontinue\n\t\t}\n\t\tname := entry.Name()\n\t\tif !strings.HasSuffix(strings.ToLower(name), \".json\") {\n\t\t\tcontinue\n\t\t}\n\t\tfull := filepath.Join(authDir, name)\n\t\tfileEntry := pluginapi.HostAuthFileEntry{\n\t\t\tName:   name,\n\t\t\tSource: \"file\",","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginhost/auth_callbacks.go#L138-L174","documentation":"listAuthFilesFromDisk needs the auth directory but h.resolvedAuthDir() returned an empty string — the host has no usable auth directory configured/resolvable, so listing auth files from disk is impossible. This is a host configuration problem, not a plugin problem.","triggerScenarios":"The auth-manager path is unavailable (manager not initialized) and the configured/fallback auth dir resolves to empty — e.g. auth-dir config empty, config not loaded, or the host started in a mode where auth storage is not file-based and no dir was resolved.","commonSituations":"Config yaml missing or with an empty auths/auth-dir setting; running the host with a config that relies on an external store (Postgres/git/object) without a local auth dir; working directory changed so relative auth dir resolution fails at startup.","solutions":["Set a concrete auth directory in config (the auths/ default, or your custom path) and confirm it exists on disk","Verify the server actually loaded the intended config file (--config path) and check startup logs for auth-dir resolution","If using an external secret store, ensure a local auth dir is still configured for plugin auth file access, or migrate plugin auth to the supported path","Restart the host after fixing config so resolvedAuthDir picks up the value"],"exampleFix":"# config.yaml — before\nauth-dir: \"\"\n\n# config.yaml — after\nauth-dir: \"./auths\"","handlingStrategy":"fallback","validationCode":"// Startup check before enabling plugins:\nif dir := host.ResolvedAuthDir(); dir == \"\" {\n    return errors.New(\"auth directory not configured; set auth-dir in config.yaml\")\n}\nif info, err := os.Stat(dir); err != nil || !info.IsDir() {\n    return fmt.Errorf(\"auth dir %s missing or not a directory\", dir)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set an explicit auth-dir in config.yaml and create it in deployment scripts","Add a startup readiness check that fails fast on empty auth dir","Mount a persistent volume for auths/ in containers"],"tags":["plugin","auth","config","filesystem"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}