risingwavelabs/risingwave · error · StreamExecutorError
Root directory does not exist
Error message
Root directory does not exist: {} What it means
The POSIX filesystem batch list source validates that the configured root directory exists on the filesystem before enumerating files. If Path::exists() is false — directory missing, deleted, unmounted, or a typo in configuration — it returns this error naming the root path, aborting the batch scan before any glob matching happens.
Solutions
- Verify the path exists on the compute node: check for container/host path mismatches and mount the directory into the pod/container if needed
- Correct typos in the source/root configuration and re-run
- Restore or recreate the missing directory, or point the source at an existing path
- Check filesystem mounts and permissions (NFS/EBS/local) if the path exists elsewhere but not on the node
Example fix
// before CREATE SOURCE ... WITH (connector = 'posix_fs', root = '/data/exports') -- path missing on node // after CREATE SOURCE ... WITH (connector = 'posix_fs', root = '/mnt/data/exports') -- verified path, mounted on node
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
fn root_dir_exists(root: &str) -> bool {
Path::new(root).is_dir()
}
// call before creating the source / running the scan:
assert!(root_dir_exists("/mnt/data/exports"), "root directory missing"); Type guard
fn is_existing_dir(p: &str) -> bool {
std::path::Path::new(p).is_dir()
} Try / catch
match list_files_to_stream(root, pattern) {
Err(e) if e.to_string().starts_with("Root directory does not exist") => {
eprintln!("check the source 'root' path and node mounts: {e}");
}
other => other?,
} Prevention
- Stat the root directory on the compute node before creating the source
- Use absolute, container-visible paths and verify mounts
- Re-check path existence after renames/deletes upstream
- Prefer connector backends (S3/Iceberg) over local FS paths when running multi-node
When it happens
Trigger: list_files_to_stream is called with a root: String whose Path::new(&root).exists() is false: the directory does not exist at scan time on the node running the executor.
Common situations: Typo in the CONNECTOR path, directory deleted or renamed between source creation and scan, running in a container where the host path isn't mounted, permission or mount failure making the path invisible.
Related errors
- ` ` must be , or
- Root directory does not exist
- actor count ( ) exceeds vnode count ( )
- additional column type
- Backfill order strategy has a cycle
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c5bd38fda5ea2d50.
Report an issue: GitHub.
Appendix: source
Thrown at src/stream/src/executor/source/batch_source/batch_posix_fs_list.rs:97
stream_source_core,
metrics,
barrier_receiver: Some(barrier_receiver),
system_params,
rate_limit_rps,
barrier_manager,
associated_table_id: associated_table_id.unwrap(),
}
}
/// List all files from root directory and convert them to a stream of chunks
async fn list_files_to_stream(
root: String,
pattern: Option<String>,
) -> StreamExecutorResult<impl Iterator<Item = StreamExecutorResult<StreamChunk>>> {
// List all files from the root directory
let root_path = Path::new(&root);
if !root_path.exists() {
return Err(anyhow!("Root directory does not exist: {}", root).into());
}
// Convert pattern string to glob::Pattern if provided
let glob_pattern = pattern
.as_ref()
.map(|p| GlobPattern::new(p))
.transpose()
.with_context(|| format!("Invalid match_pattern: {:?}", pattern))?;
let mut files = Vec::new();
Self::collect_files_recursive(root_path, root_path, &glob_pattern, &mut files).await?;
tracing::debug!(
"BatchPosixFsListExecutor listed {} files from {}: {:?}",
files.len(),
root,
files
);View on GitHub (pinned to 6469eb736d)