risingwavelabs/risingwave · error
the target_dir must not include source_dir
Error message
the target_dir must not include source_dir
What it means
After trimming trailing slashes, the migration command checks that target_dir is not nested inside source_dir. If it were, moving objects would overwrite or corrupt the source being iterated, so it refuses to run.
Source
Thrown at src/ctl/src/cmd_impl/hummock/migrate_legacy_object.rs:44
use risingwave_object_store::object::{
ObjectStoreImpl, OpendalObjectStore, build_remote_object_store,
};
pub async fn migrate_legacy_object(
url: String,
source_dir: String,
target_dir: String,
concurrency: u32,
) -> anyhow::Result<()> {
let source_dir = source_dir.trim_end_matches('/');
let target_dir = target_dir.trim_end_matches('/');
println!("Normalized source_dir: {source_dir}.");
println!("Normalized target_dir: {target_dir}.");
if source_dir.is_empty() || target_dir.is_empty() {
return Err(anyhow!("the source_dir and target_dir must not be empty"));
}
if target_dir.starts_with(source_dir) {
return Err(anyhow!("the target_dir must not include source_dir"));
}
let mut config = ObjectStoreConfig::default();
config.s3.developer.use_opendal = true;
let store = build_remote_object_store(
&url,
ObjectStoreMetrics::unused().into(),
"migrate_legacy_object",
config.into(),
)
.await;
let ObjectStoreImpl::Opendal(opendal) = store else {
return Err(anyhow!("OpenDAL is required"));
};
let mut iter = opendal.list(source_dir, None, None).await?;
let mut count = 0;
println!("Migration is started: from {source_dir} to {target_dir}.");
let mut from_to = Vec::with_capacity(concurrency as usize);
let timer = Instant::now();View on GitHub (pinned to 6469eb736d)
Solutions
- Choose a target_dir that does not begin with source_dir (e.g. source 'legacy', target 'objects')
- Swap direction if you intended the reverse nesting — that is also rejected the same way
- Copy to a separate bucket/prefix if a nested layout is genuinely required
Example fix
// before --source-dir 'hummock' --target-dir 'hummock/v2' // after --source-dir 'hummock' --target-dir 'hummock-v2'
Defensive patterns
Strategy: validation
Validate before calling
if target_dir.trim_end_matches('/').starts_with(source_dir.trim_end_matches('/')) {
panic!("target_dir must not be nested within source_dir");
} Prevention
- Pick target prefixes disjoint from the source prefix
- Sketch the before/after key layout before migrating
- Avoid in-place subdirectory migrations
When it happens
Trigger: Running migrate-legacy-object with target_dir starting with source_dir, e.g. source 'data' and target 'data/new', or source 'a' and target 'a/b'.
Common situations: Migrating to a subdirectory of the legacy layout; typos where target accidentally shares the source prefix; planning an in-place layout change.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- the source_dir and target_dir must not be empty
- the source object store does not appear to be legacy: {} ver
- OpenDAL is required
- Storage error: {0}
- Invalid value `{value}` for `{entry}`
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/de2da9746359ed32.
Report an issue: GitHub.