router-for-me/CLIProxyAPI · error
invalid log file
Error message
invalid log file
What it means
logFileMatchesCursor os.Stat'ed a path that is a directory, which cannot be a log file for cursor-based log listing/polling. The cursor logic compares size, modification time, and content fingerprints of regular files; a directory breaks those invariants, so it is rejected explicitly instead of returning misleading size/modtime data.
Source
Thrown at internal/api/handlers/management/logs.go:876
}
return false
}
func logFileChangedAfterCursor(path string, cursor logCursor) bool {
info, errStat := os.Stat(path)
if errStat != nil || info.IsDir() || info.Size() == 0 {
return false
}
return info.ModTime().UnixNano() > cursorModTimeUnixNano(cursor)
}
func logFileMatchesCursor(path string, cursor logCursor) (bool, bool, error) {
info, errStat := os.Stat(path)
if errStat != nil {
return false, false, errStat
}
if info.IsDir() {
return false, false, fmt.Errorf("invalid log file")
}
if info.Size() < cursor.Offset {
return false, true, nil
}
boundary := cursorFingerprintBoundary(cursor)
if info.Size() < boundary {
return false, true, nil
}
fingerprint, errFingerprint := logFileFingerprint(path, boundary)
if errFingerprint != nil {
return false, false, errFingerprint
}
return fingerprint == cursor.Fingerprint, false, nil
}
func encodeLogCursor(cursor logCursor) (string, error) {
raw, err := json.Marshal(cursor)
if err != nil {View on GitHub (pinned to 78f0c4079e)
Solutions
- Check the configured log-file path and make sure it names a regular file (ls -ld on the exact path)
- Fix mount points that overlay the log path with a directory in containers
- Reconfigure the logger to write to a proper filename (e.g. logs/app.log, not logs/)
- If passing paths as request parameters, reject directory paths client-side before calling the logs API
Example fix
# before (config.yaml) log-file: /app/logs # a directory # after (config.yaml) log-file: /app/logs/app.log
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(path)
if err == nil && info.IsDir() {
return fmt.Errorf("%s is a directory; configure a regular file for logging", path)
} Type guard
func isRegularFile(path string) bool {
info, err := os.Stat(path)
return err == nil && info.Mode().IsRegular()
} Try / catch
if _, _, err := logFileMatchesCursor(path, cursor); err != nil {
if strings.Contains(err.Error(), "invalid log file") { /* fix log-file config; skip this path */ }
} Prevention
- Point log-file at a filename, not a directory
- In containers, mount the parent dir rather than overlaying the file path
- Validate any path parameter client-side against directory entries
When it happens
Trigger: Log-tail or poll endpoints where the computed log path, or an entry in the log listing, resolves to a directory — log-file config set to a directory, a container mount mapping a directory over the configured log filename, or a request path parameter that names a directory.
Common situations: Misconfigured logging section pointing log-file at a directory; container volume mounts overlaying the log path; log-rotation tooling replacing files with directories; users passing arbitrary paths to the log download API.
Related errors
- home tls: read ca-cert: %w
- failed to write file: %w
- failed to remove file: %w
- failed to read auth file: %w
- failed to update source auth file: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/98d4a185e7f7f3f6.
Report an issue: GitHub.