risingwavelabs/risingwave · error

the source object store does not appear to be legacy: {} ver

Error message

the source object store does not appear to be legacy: {} versus {}

What it means

While listing objects under source_dir, the tool derives the expected legacy path for each object and compares it with the actual key. A mismatch means the store contains objects that do not match the legacy naming scheme, so a mechanical migration would be unsafe.

Source

Thrown at src/ctl/src/cmd_impl/hummock/migrate_legacy_object.rs:86

        {
            let legacy_path = object.key;
            assert_eq!(
                &legacy_path[..source_dir.len()],
                source_dir,
                "{legacy_path} versus {source_dir}"
            );
            if legacy_path.ends_with('/') {
                tracing::warn!(legacy_path, "skip directory");
                continue;
            }
            let new_path = format!("{}{}", target_dir, &legacy_path[source_dir.len()..]);
            from_to.push((legacy_path, new_path));
        } else {
            let object_id = get_object_id_from_path(&object.key);
            let legacy_prefix = get_object_prefix(object_id.as_raw().as_raw_id(), false);
            let legacy_path = get_object_data_path(&legacy_prefix, source_dir, object_id);
            if object.key != legacy_path {
                return Err(anyhow!(format!(
                    "the source object store does not appear to be legacy: {} versus {}",
                    object.key, legacy_path
                )));
            }
            let new_path = get_object_data_path(
                &get_object_prefix(object_id.as_raw().as_raw_id(), true),
                target_dir,
                object_id,
            );
            from_to.push((legacy_path, new_path));
        }
        count += 1;
        if from_to.len() >= concurrency as usize {
            copy(std::mem::take(&mut from_to).into_iter(), opendal.inner()).await?;
        }
    }
    if !from_to.is_empty() {
        copy(from_to.into_iter(), opendal.inner()).await?;

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Inspect the two reported paths to identify the offending object and remove/move it if it does not belong
  2. Resume a partial migration from where it stopped instead of re-listing mixed content
  3. Ensure source_dir points only at the legacy object directory
  4. Verify which prefix strategy (new vs legacy) the objects actually use before migrating

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

let expected = get_object_data_path(&get_object_prefix(id.as_raw().as_raw_id(), false), source_dir, &object_id);
if listed_key != expected {
    eprintln!("non-legacy object found: {} (expected {})", listed_key, expected);
}

Prevention

When it happens

Trigger: The listed object's key equals neither the new-prefix path nor the recomputed legacy path — e.g. partially migrated store, hand-copied objects, or objects from a different prefix scheme inside source_dir.

Common situations: Re-running migration after a partial run; mixing old/new object prefixes in one directory; pointing source_dir at a directory containing unrelated objects.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/8e26e5ed73b73a99. Report an issue: GitHub.