{"record":{"id":"2ce4e67e23c3e249","repo":"risingwavelabs/risingwave","slug":"opendal-is-required","errorCode":null,"errorMessage":"OpenDAL is required","messagePattern":"OpenDAL is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/ctl/src/cmd_impl/hummock/migrate_legacy_object.rs","lineNumber":56,"sourceCode":"    println!(\"Normalized source_dir: {source_dir}.\");\n    println!(\"Normalized target_dir: {target_dir}.\");\n    if source_dir.is_empty() || target_dir.is_empty() {\n        return Err(anyhow!(\"the source_dir and target_dir must not be empty\"));\n    }\n    if target_dir.starts_with(source_dir) {\n        return Err(anyhow!(\"the target_dir must not include source_dir\"));\n    }\n    let mut config = ObjectStoreConfig::default();\n    config.s3.developer.use_opendal = true;\n    let store = build_remote_object_store(\n        &url,\n        ObjectStoreMetrics::unused().into(),\n        \"migrate_legacy_object\",\n        config.into(),\n    )\n    .await;\n    let ObjectStoreImpl::Opendal(opendal) = store else {\n        return Err(anyhow!(\"OpenDAL is required\"));\n    };\n    let mut iter = opendal.list(source_dir, None, None).await?;\n    let mut count = 0;\n    println!(\"Migration is started: from {source_dir} to {target_dir}.\");\n    let mut from_to = Vec::with_capacity(concurrency as usize);\n    let timer = Instant::now();\n    while let Some(object) = iter.next().await {\n        let object = object?;\n        if !VALID_OBJECT_ID_SUFFIXES\n            .iter()\n            .any(|suffix| object.key.ends_with(suffix))\n        {\n            let legacy_path = object.key;\n            assert_eq!(\n                &legacy_path[..source_dir.len()],\n                source_dir,\n                \"{legacy_path} versus {source_dir}\"\n            );","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/ctl/src/cmd_impl/hummock/migrate_legacy_object.rs#L38-L74","documentation":"The migration tool builds a remote object store from the given URL and requires the resulting backend to be an OpenDAL-backed store, since the list/copy rewrite logic uses OpenDAL APIs. Any other ObjectStoreImpl variant causes this error.","triggerScenarios":"Running migrate-legacy-object with a store URL that resolves to a non-OpenDAL implementation (e.g. native S3 client instead of OpenDAL S3).","commonSituations":"Using an s3:// URL while the OpenDAL developer option is not applied to the backend selection, or pointing at an in-memory/local store type.","solutions":["Provide an object store URL that builds an OpenDAL backend (opendal s3 url)","Check the rw build/feature flags enable OpenDAL object store support","Inspect build_remote_object_store's URL mapping to confirm which URL forms yield ObjectStoreImpl::Opendal"],"exampleFix":"null","handlingStrategy":"fallback","validationCode":"let store = build_remote_object_store(&url, ...).await;\nif !matches!(store, ObjectStoreImpl::Opendal(_)) {\n    eprintln!(\"url {} does not yield an OpenDAL backend\", url);\n    return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Confirm which ObjectStoreImpl variants your build maps each URL scheme to","Enable OpenDAL feature flags in the build","Test store construction with a small listing before migrating"],"tags":["object-store","opendal","cli","unsupported-backend"],"backgroundTag":"incompatible-source-type","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}