@@ -520,6 +520,12 @@ async def copy_dir(src_dir: str, dest_dir: str) -> None:
520520 await makedirs (dest_dir , exist_ok = True )
521521 # Determine the source filesystem independently of destination
522522 src_fs , _ = _get_fs_for_path (src_dir )
523+ # Remember protocol for remote paths so that we can reconstruct full URIs
524+ # from keys returned by fsspec (which may omit the protocol).
525+ src_protocol : Optional [str ] = None
526+ if is_remote_path (src_dir ):
527+ src_protocol = src_dir .split ("://" , 1 )[0 ]
528+
523529 try :
524530 src_files = src_fs .find (src_dir )
525531 except Exception :
@@ -529,8 +535,14 @@ async def copy_dir(src_dir: str, dest_dir: str) -> None:
529535 for f in files :
530536 src_files .append (f )
531537
532- for src_file in src_files :
533- # Compute relative path with respect to the source dir
538+ for raw_src_file in src_files :
539+ # For remote filesystems, ensure we have a full URI (e.g., s3://bucket/...)
540+ src_file = raw_src_file
541+ if src_protocol is not None and not is_remote_path (raw_src_file ):
542+ src_file = f"{ src_protocol } ://{ raw_src_file .lstrip ('/' )} "
543+
544+ # Compute relative path with respect to the source dir using the
545+ # normalized src_file URI/path.
534546 rel_path = src_file [len (src_dir ) :].lstrip ("/" )
535547 dest_file = join (dest_dir , rel_path )
536548 # Ensure destination directory exists
0 commit comments