router-for-me/CLIProxyAPI · error
failed to read auth dir
Error message
failed to read auth dir: %w
What it means
os.ReadDir on the resolved auth directory failed; the wrapped error carries the OS cause (most commonly 'no such file or directory' or 'permission denied'). The plugin's attempt to enumerate auth files fails at the filesystem level.
Solutions
- Create the directory: mkdir -p <auth-dir> with ownership matching the server user
- Check the exact OS error in the wrapped message: ENOENT → create/mount the dir, EACCES → chmod/chown the dir
- Verify the configured path spelling and that the container/host mounts it
- Restart or retry once the filesystem is fixed
Example fix
mkdir -p ./auths && chown $(id -u):$(id -g) ./auths
Defensive patterns
Strategy: fallback
Validate before calling
// Pre-flight before listing auth files:
dir := host.ResolvedAuthDir()
if dir == "" {
return errors.New("auth dir unresolved")
}
if _, err := os.Stat(dir); err != nil {
if mkErr := os.MkdirAll(dir, 0o700); mkErr != nil { return mkErr }
} Prevention
- Create the auth dir in entrypoint scripts (mkdir -p) with correct ownership
- Run the server under a user with read access to the auth dir
- Mount the auths volume in containers and verify with a healthcheck
When it happens
Trigger: Auth dir path exists in config but is absent on disk (deleted, never created, wrong volume mounted), or the process lacks read/execute permission on it, or it was replaced by a file.
Common situations: Container deployment missing a volume mount for auths/; auth dir removed by cleanup scripts; permissions changed after running as a different user; typo in the configured path.
Related errors
- pluginhost: save command-line auth
- auth directory is unavailable
- failed to create directory
- failed to create directory
- failed to create token file
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/08d0cce29e6a689e.
Report an issue: GitHub.
Appendix: source
Thrown at internal/pluginhost/auth_callbacks.go:160
entries = append(entries, *entry)
}
}
sort.Slice(entries, func(i, j int) bool {
return strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name)
})
return entries, nil
}
return h.listAuthFilesFromDisk()
}
func (h *Host) listAuthFilesFromDisk() ([]pluginapi.HostAuthFileEntry, error) {
authDir := h.resolvedAuthDir()
if authDir == "" {
return nil, fmt.Errorf("auth directory is unavailable")
}
entries, errReadDir := os.ReadDir(authDir)
if errReadDir != nil {
return nil, fmt.Errorf("failed to read auth dir: %w", errReadDir)
}
files := make([]pluginapi.HostAuthFileEntry, 0)
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if !strings.HasSuffix(strings.ToLower(name), ".json") {
continue
}
full := filepath.Join(authDir, name)
fileEntry := pluginapi.HostAuthFileEntry{
Name: name,
Source: "file",
Path: full,
}
if info, errInfo := entry.Info(); errInfo == nil {
fileEntry.Size = info.Size()View on GitHub (pinned to 78f0c4079e)