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

  1. Check the configured log-file path and make sure it names a regular file (ls -ld on the exact path)
  2. Fix mount points that overlay the log path with a directory in containers
  3. Reconfigure the logger to write to a proper filename (e.g. logs/app.log, not logs/)
  4. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/98d4a185e7f7f3f6. Report an issue: GitHub.