router-for-me/CLIProxyAPI · warning
invalid fingerprint boundary
Error message
invalid fingerprint boundary
What it means
Returned by logFileFingerprint (logs.go:1035) when the boundary (the byte position up to which the file is fingerprinted) exceeds the file's current size. newLogCursor computes the boundary from the offset/size it just Stat'ed; if the file shrinks between that Stat and the Open/Stat inside logFileFingerprint, the boundary is now past EOF and the check trips. It is a time-of-check/time-of-use race during rotation or truncation.
Source
Thrown at internal/api/handlers/management/logs.go:1035
if boundary < 0 {
return "", fmt.Errorf("invalid fingerprint boundary")
}
file, errOpen := os.Open(path)
if errOpen != nil {
return "", errOpen
}
defer func() {
_ = file.Close()
}()
info, errStat := file.Stat()
if errStat != nil {
return "", errStat
}
if info.IsDir() {
return "", fmt.Errorf("invalid log file")
}
if boundary > info.Size() {
return "", fmt.Errorf("invalid fingerprint boundary")
}
hash := sha256.New()
_, _ = fmt.Fprintf(hash, "log-cursor-v1:%d:", boundary)
firstLen := minInt64(boundary, logCursorFingerprintMax)
if errRead := writeFileRange(hash, file, 0, firstLen); errRead != nil {
return "", errRead
}
tailLen := minInt64(boundary, logCursorFingerprintMax)
tailStart := boundary - tailLen
_, _ = fmt.Fprintf(hash, ":%d:", tailStart)
if errRead := writeFileRange(hash, file, tailStart, tailLen); errRead != nil {
return "", errRead
}
sum := hash.Sum(nil)
return base64.RawURLEncoding.EncodeToString(sum[:12]), nil
}
View on GitHub (pinned to 78f0c4079e)
Solutions
- Retry the same log request once — the race is transient and the retry will compute a fresh boundary against the new file size
- Switch rotation from copytruncate to rename+create so the active file is replaced atomically instead of being truncated in place
- If it persists, check that no process is continuously truncating the log file
- Start a fresh read without a cursor to resynchronize state
Example fix
# before: copytruncate shrinks the file mid-fingerprint
/var/log/cliproxy/cliproxy.log {
copytruncate
weekly
}
# after: rename-based rotation avoids in-place truncation
/var/log/cliproxy/cliproxy.log {
create 0644 root root
postrotate
systemctl reload cliproxy || true
endscript
} Defensive patterns
Strategy: retry
Try / catch
for attempt := 0; attempt < 2; attempt++ {
cursor, err := newLogCursor(path, offset, latest)
if err == nil {
break
}
if strings.Contains(err.Error(), "invalid fingerprint boundary") && attempt == 0 {
continue // rotation raced us; recompute offset against new size
}
return err
} Prevention
- Use atomic (rename-based) rotation so files are never truncated in place while being read
- Schedule log rotation and aggressive log-trimming jobs away from heavy dashboard polling windows
- Retry once on boundary-size errors before surfacing them to users
When it happens
Trigger: Log rotation or copytruncate fires exactly between newLogCursor's os.Stat and logFileFingerprint's open+stat, shrinking the file; rapid manual truncation while a tail client paginates.
Common situations: logrotate with copytruncate running on a busy server; a disk-cleanup job that truncates logs on a schedule that collides with dashboard polling.
Related errors
- invalid cursor offset
- Codex live media session closed while configuring TCP proxy
- invalid log offset
- must be a positive integer
- must be greater than zero
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/4598e292dce2bbd4.
Report an issue: GitHub.