tikv/tikv · error

start_key must be in data-key space

Error message

start_key must be in data-key space

What it means

`get_region_approximate_middle_in_range` in components/raftstore/src/coprocessor/split_check/half.rs:137 requires caller-supplied `start_key` to be in the encoded data-key space. `keys::validate_data_key` fails for keys not beginning with the data prefix (e.g. raw/meta keys), so an io::Error with InvalidInput and "start_key must be in data-key space" is returned. The function computes a middle split key, which is only meaningful for data keys.

Source

Thrown at components/raftstore/src/coprocessor/split_check/half.rs:137

}

/// Get region approximate middle key from an explicit encoded data-key range.
///
/// The provided range must be in the `keys::data_key` / `keys::data_end_key`
/// space. It is clamped to region boundaries. When the resulting range is
/// empty, returns `Ok(None)`.
pub fn get_region_approximate_middle_in_range(
    db: &impl KvEngine,
    region: &Region,
    start_key: Option<&[u8]>,
    end_key: Option<&[u8]>,
) -> Result<Option<Vec<u8>>> {
    let region_start_key = keys::enc_start_key(region);
    let region_end_key = keys::enc_end_key(region);

    if let Some(start_key) = start_key {
        if !keys::validate_data_key(start_key) {
            return box_try!(Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "start_key must be in data-key space",
            )));
        }
    }
    if let Some(end_key) = end_key {
        if !keys::validate_data_key(end_key) && end_key != keys::DATA_MAX_KEY {
            return box_try!(Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "end_key must be in data-key space",
            )));
        }
    }
    let start_key = match start_key {
        Some(start_key) if start_key > region_start_key.as_slice() => start_key.to_vec(),
        _ => region_start_key,
    };
    let end_key = match end_key {

View on GitHub (pinned to 78aedc1c81)

Solutions

  1. Encode the start key with `keys::encode_data_key` / the `keys` module helpers so `validate_data_key` passes.
  2. Confirm the key comes from the data CF space (starts with the data-key prefix 'z') before passing it.
  3. If the intent is to cover from the region start, pass `None` for start_key instead of a non-data key.
  4. Fix the caller (e.g. bucket rule or split request) that is generating out-of-space keys.

Example fix

// before
let middle = get_region_approximate_middle(db, region, Some(raw_key.to_vec()), None, "write")?;
// after
let enc_key = keys::encode_data_key(raw_key);
assert!(keys::validate_data_key(&enc_key));
let middle = get_region_approximate_middle(db, region, Some(enc_key), None, "write")?;
Defensive patterns

Strategy: validation

Validate before calling

use tikv_util::keybuilder // keys module
if !keys::validate_data_key(&start_key) {
    return Err("start_key must be encoded into data-key space".into());
}

Type guard

fn is_data_key(k: &[u8]) -> bool { keys::validate_data_key(k) }

Try / catch

match middle_result {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput
        && e.to_string().contains("start_key must be in data-key space") => {
        // re-encode the key or pass None and retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `get_region_approximate_middle_in_range` (or `get_region_approximate_middle` that forwards the range) with `Some(start_key)` where `keys::validate_data_key(start_key)` is false — i.e. the key is not in the data-key space (not a properly encoded user-data key).

Common situations: Passing a raw table key instead of the TiKV-encoded key; passing keys::ENC_PREFIX/meta keys; using un-encoded keys copied from another system; bucket/split-range tooling (e.g. region buckets or manual split commands) supplying out-of-space keys.

Related errors


AI-assisted analysis of tikv/tikv@78aedc1c81 (2026-09-03). Data as JSON: /api/errors/7f845a875ef14a67. Report an issue: GitHub.