risingwavelabs/risingwave · error

the source_dir and target_dir must not be empty

Error message

the source_dir and target_dir must not be empty

What it means

The legacy object migration command trims trailing slashes from source_dir/target_dir and rejects either being empty, because migrating to or from the bucket root is not supported by the path-relative rewrite logic. It fails fast before touching the object store.

Source

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

};
use risingwave_object_store::object::object_metrics::ObjectStoreMetrics;
use risingwave_object_store::object::prefix::opendal_engine::get_object_prefix;
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;

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Pass explicit non-empty relative directory prefixes for both source_dir and target_dir
  2. If you truly need whole-bucket migration, restructure so objects live under a common prefix
  3. Check shell quoting/variable expansion isn't producing an empty argument

Example fix

// before
rw hummock migrate-legacy-object --source-dir '' --target-dir 'new/'
// after
rw hummock migrate-legacy-object --source-dir 'legacy' --target-dir 'new'
Defensive patterns

Strategy: validation

Validate before calling

let s = source_dir.trim_end_matches('/');
let t = target_dir.trim_end_matches('/');
if s.is_empty() || t.is_empty() {
    panic!("source_dir and target_dir must be non-empty (not '/')");
}

Prevention

When it happens

Trigger: Running `rw hummock migrate-legacy-object` with an empty or '/'-only source_dir or target_dir argument.

Common situations: Omitting the --source-dir/--target-dir flags entirely; passing '/' intending 'whole bucket'; script variables defaulting to empty strings.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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