neondatabase/neon · error
spread_factor must be >= 0, got {}
Error message
spread_factor must be >= 0, got {} What it means
FileCacheConfig::validate also enforces spread_factor >= 0.0. spread_factor (default 0.1) reserves bytes for the rest of the system while the cache grows, per size = (total - min_remaining_after_cache)/(spread_factor + 1); a negative value is meaningless there. Note the additional cross-check resource_multiplier * (spread_factor + 1) < 1.0.
Source
Thrown at libs/vm_monitor/src/filecache.rs:81
// 256 MiB - lower than when in memory because overcommitting is safe; if we don't have
// memory, the kernel will just evict from its page cache, rather than e.g. killing
// everything.
min_remaining_after_cache: NonZeroU64::new(256 * MiB).unwrap(),
spread_factor: 0.1,
}
}
}
impl FileCacheConfig {
/// Make sure fields of the config are consistent.
pub fn validate(&self) -> anyhow::Result<()> {
// Single field validity
anyhow::ensure!(
0.0 < self.resource_multiplier && self.resource_multiplier < 1.0,
"resource_multiplier must be between 0.0 and 1.0 exclusive, got {}",
self.resource_multiplier
);
anyhow::ensure!(
self.spread_factor >= 0.0,
"spread_factor must be >= 0, got {}",
self.spread_factor
);
// Check that `resource_multiplier` and `spread_factor` are valid w.r.t. each other.
//
// As shown in `calculate_cache_size`, we have two lines resulting from `resource_multiplier` and
// `spread_factor`, respectively. They are:
//
// `total` `min_remaining_after_cache`
// size = ————————————————————— - —————————————————————————————
// `spread_factor` + 1 `spread_factor` + 1
//
// and
//
// size = `resource_multiplier` × total
//View on GitHub (pinned to 8f60b04da4)
Solutions
- Use 0.0 or a small positive value like the default 0.1
- Verify the combined constraint resource_multiplier * (spread_factor + 1.0) < 1.0 also holds
- Validate config once at startup and fail fast with the message
Example fix
// before
let config = FileCacheConfig { spread_factor: -0.1, ..Default::default() };
config.validate()?; // Err: spread_factor must be >= 0
// after
let config = FileCacheConfig { spread_factor: 0.1, ..Default::default() };
config.validate()?; // Ok Defensive patterns
Strategy: validation
Validate before calling
fn valid_spread_factor(v: f64) -> bool {
v >= 0.0
}
// also honor the cross-field rule: resource_multiplier * (spread_factor + 1.0) < 1.0
anyhow::ensure!(valid_spread_factor(spread), "spread_factor must be >= 0.0, got {spread}"); Try / catch
if let Err(e) = config.validate() {
if e.to_string().contains("spread_factor") {
// config error: log the value and exit(1) with a clear message
}
return Err(e);
} Prevention
- Clamp externally sourced spread_factor values to >= 0.0 before use
- Validate the combined constraint resource_multiplier * (spread_factor + 1.0) < 1.0 in config tests
- Prefer FileCacheConfig::default() unless tuning is actually needed
When it happens
Trigger: Constructing FileCacheConfig with a negative spread_factor and calling validate(), e.g. from a sign typo in tuning code or a computed value that can dip below zero.
Common situations: Hand-tuned cache configs; values derived from telemetry deltas that go negative under noise.
Related errors
- resource_multiplier must be between 0.0 and 1.0 exclusive, g
- incompatible resource_multipler and spread_factor
- invalid monitor Config: sys_buffer_bytes cannot be 0
- could not parse config file: {}
- could not open config file at path: {}
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/109bf5e700873036.
Report an issue: GitHub.