influxdata/influxdb · warning
sharder mapped input to non-existant bucket
Error message
sharder mapped input to non-existant bucket
What it means
JumpHash implements Google's jump consistent hash: the loop advances bucket b while j < shards.len(), so on exit b must be a valid index. The .expect('sharder mapped input to non-existant bucket') is a defensive invariant guard after assert!(b >= 0) — by construction of the loop it should be unreachable, because b always holds a j that was < shards.len(). Seeing it means the jump-hash arithmetic produced an out-of-range bucket (e.g. an f64-to-i64 cast edge in the j computation) or the shards vector was mutated/aliased after construction.
Source
Thrown at core/sharder/src/jumphash.rs:104
H: Hash,
{
let mut state = self.hasher;
key.hash(&mut state);
let mut key = state.finish();
let mut b = -1;
let mut j = 0;
while j < self.shards.len() as i64 {
b = j;
key = key.wrapping_mul(2862933555777941757).wrapping_add(1);
j = ((b.wrapping_add(1) as f64) * (((1u64 << 31) as f64) / (((key >> 33) + 1) as f64)))
as i64
}
assert!(b >= 0);
self.shards
.get(b as usize)
.expect("sharder mapped input to non-existant bucket")
}
/// Consistently hash a table and namespace to a `T`. For use in a situation where you don't
/// have a payload.
pub fn shard_for_query(&self, table: &str, namespace: &str) -> &T {
// The derived hash impl for HashKey is hardened against prefix
// collisions when combining the two fields.
self.hash(&HashKey { table, namespace })
}
}
#[derive(Hash)]
struct HashKey<'a> {
table: &'a str,
namespace: &'a str,
}
/// A [`JumpHash`] sharder mapping a [`MutableBatch`] reference according to theView on GitHub (pinned to d28e26e048)
Solutions
- Treat it as a bug: capture the key, shards.len(), and crate versions and file an issue against the sharder crate — do not try to 'fix' it in calling code.
- Verify the JumpHash instance is not constructed once and then have its shard list changed underneath (immutability guarantees shards order); rebuild the sharder when topology changes.
- Ensure the constructor path ran (the 'empty shard set given to sharder' assert) so an empty shard set fails fast at startup instead of at first hash.
- Pin dependency versions (siphasher) so hash/cast behavior matches the tested build; the repo keeps test_key_bucket_fixture for exactly this mapping stability.
Example fix
// No caller-side fix: b is guaranteed < shards.len() by the loop.
// If hit, add a reproducing test:
#[test]
fn repro_out_of_bounds_bucket() {
let hasher = JumpHash::new((0..1_000).map(Arc::new));
for k in 0..1_000_000u64 {
let _ = hasher.hash(k); // panics here => jump-hash math bug, report upstream
}
} Defensive patterns
Strategy: validation
Validate before calling
// The constructor already asserts non-empty; validate before building:
let shards: Vec<_> = nodes.collect();
if shards.is_empty() {
return Err("refusing to start with zero shards");
}
let sharder = JumpHash::new(shards); Type guard
fn has_shards<T>(v: &[T]) -> bool { !v.is_empty() } Prevention
- Fail fast on empty shard sets at topology load time (the JumpHash::new assert exists for this).
- Never rebuild or reorder the shard list after handing it to JumpHash — rebuild a new sharder instead.
- Pin sharder dependency versions; the repo's test_key_bucket_fixture pins the key->bucket mapping across upgrades.
When it happens
Trigger: Calling JumpHash::hash / shard / shard_for_query on a sharder whose internal state no longer matches what the loop assumed. The constructor already asserts a non-empty shard set, so an empty shard list panics earlier ('empty shard set given to sharder'), not here. In practice this expect has no normal trigger; it fires only on an implementation bug or memory corruption of the shards Vec.
Common situations: Almost never seen; if reported, it follows a dependency upgrade that changed integer/float casting behavior in the jump-hash loop, a fork that altered the shard list after construction, or a corrupted Vec. InfluxDB Enterprise router/sharding code paths (sharding data by table+namespace across nodes) would be the place it surfaces.
Related errors
- mapped to out-of-bounds shard
- num_columns_in_parallel should be above zero
- If you call `drop_last_value`, the tag buffer must contain a
- If we can remove a value from the interned strings, we must
- must have offset
AI-assisted analysis of influxdata/influxdb@d28e26e048 (2026-08-16).
Data as JSON: /api/errors/93957a5ffed762d5.
Report an issue: GitHub.