redis/node-redis · error · Error
All statistics values must be non-negative
Error message
All statistics values must be non-negative
What it means
CacheStats' constructor (reached via CacheStats.of) enforces that all six counters (hitCount, missCount, loadSuccessCount, loadFailureCount, totalLoadTime, evictionCount) are >= 0. A negative value would corrupt every derived rate (hitRate, missRate, loadFailureRate) and break the Caffeine-style stats contract, so the constructor rejects it outright.
Source
Thrown at packages/client/lib/client/cache.ts:51
* Creates a new CacheStats instance with the specified statistics.
*/
private constructor(
public readonly hitCount: number,
public readonly missCount: number,
public readonly loadSuccessCount: number,
public readonly loadFailureCount: number,
public readonly totalLoadTime: number,
public readonly evictionCount: number
) {
if (
hitCount < 0 ||
missCount < 0 ||
loadSuccessCount < 0 ||
loadFailureCount < 0 ||
totalLoadTime < 0 ||
evictionCount < 0
) {
throw new Error('All statistics values must be non-negative');
}
}
/**
* Creates a new CacheStats instance with the specified statistics.
*
* @param hitCount - Number of cache hits
* @param missCount - Number of cache misses
* @param loadSuccessCount - Number of successful cache loads
* @param loadFailureCount - Number of failed cache loads
* @param totalLoadTime - Total load time in milliseconds
* @param evictionCount - Number of cache evictions
*/
static of(
hitCount = 0,
missCount = 0,
loadSuccessCount = 0,
loadFailureCount = 0,View on GitHub (pinned to bb5beb5657)
Solutions
- Ensure all record*(value) calls receive non-negative values (clamp with Math.max(0, value)).
- If authoring a custom StatsCounter, guard recordHits/recordMisses/recordEvictions to reject negative counts and recordLoadSuccess/recordLoadFailure to reject negative times.
- Audit the call sites that construct CacheStats directly (most users should only read snapshots).
Example fix
// before counter.recordLoadSuccess(negativeElapsed); // after counter.recordLoadSuccess(Math.max(0, negativeElapsed));
Defensive patterns
Strategy: validation
Validate before calling
function safeRecord(counter, fn, value) {
if (typeof value === 'number' && value >= 0) fn.call(counter, value);
} Type guard
function isNonNegativeNumber(v: unknown): v is number {
return typeof v === 'number' && Number.isFinite(v) && v >= 0;
} Prevention
- Clamp all counter inputs with Math.max(0, value).
- Guard custom StatsCounter record* methods against negative arguments.
- Avoid constructing CacheStats directly; read snapshots via the counter.
When it happens
Trigger: Calling CacheStats.of(...) with a negative argument directly; a StatsCounter.recordX(-n) producing a negative running total whose snapshot is then built; an arithmetic underflow in a custom StatsCounter; subtraction (minus) already clamps with Math.max(0,...), so hitting this implies a non-clamped code path.
Common situations: A custom StatsCounter that doesn't guard against negative inputs; concurrent decrement logic; test fixtures passing negative numbers; a bug where recordLoadFailure is called with a negative elapsed time.
Related errors
- "arguments[${i}]" must be of type "string | Buffer", got ${t
- expirationRefreshRatio must be less than or equal to 1
- expirationRefreshRatio must be greater or equal to 0
- HIMPORT PREPARE/DISCARD/DISCARDALL are not supported inside
- tls socket option is set to ${options.socket.tls} which is m
AI-assisted analysis of redis/node-redis@bb5beb5657 (2026-08-03).
Data as JSON: /data/errors/e4e61100aec4b8f8.json.
Report an issue: GitHub.