langflow-ai/langflow · error · SystemExit

{provider}: source has subdirectory/ies {subdirs} that move_

Error message

{provider}: source has subdirectory/ies {subdirs} that move_provider does not relocate (it copies only top-level *.py modules). Use port_bundle.py, which handles nested subpackages, instead.

What it means

move_provider() copies only top-level *.py modules but rmtree's the entire source tree afterwards. If the provider directory contained real subpackages (anything except __pycache__), those subdirectories would be silently destroyed — never copied to the bundle and never added to the migration mapping. To prevent that data loss, the script detects subdirectories and hard-fails, directing you to port_bundle.py, which handles nested subpackage layouts (e.g. agentics/helpers) correctly.

Source

Thrown at scripts/migrate/consolidate_bundles.py:297

        msg = f"provider directory not found: {src}"
        raise SystemExit(msg)
    if dst.exists():
        msg = f"destination already exists (already consolidated?): {dst}"
        raise SystemExit(msg)

    # move_provider relocates only top-level ``*.py`` modules (see the glob
    # below) but rmtree's the whole source tree.  A provider with a subpackage
    # would have its subdir silently destroyed -- never copied to the bundle and
    # never migration-mapped.  Refuse rather than half-move; port_bundle.py is
    # the tool for nested layouts.
    subdirs = sorted(p.name for p in src.iterdir() if p.is_dir() and p.name != "__pycache__")
    if subdirs:
        msg = (
            f"{provider}: source has subdirectory/ies {subdirs} that move_provider does not "
            "relocate (it copies only top-level *.py modules). Use port_bundle.py, which "
            "handles nested subpackages, instead."
        )
        raise SystemExit(msg)

    classes = discover_component_classes(src)
    py_files = sorted(src.glob("*.py"))
    print(f"  {provider}: {len(py_files)} file(s), {len(classes)} component class(es) -> {dst.relative_to(REPO_ROOT)}")
    for module_stem, class_name in classes:
        print(f"      {module_stem}.{class_name} -> ext:{slug}:{class_name}@official")

    if not apply:
        return classes

    dst.mkdir(parents=True)
    for py in py_files:
        content = _rewrite_self_imports(py.read_text(encoding="utf-8"), provider, slug)
        (dst / py.name).write_text(content, encoding="utf-8")
    # Remove the moved source, then replace the in-tree dir with a one-file shim.
    shutil.rmtree(src)
    src.mkdir()
    (src / "__init__.py").write_text(_shim_source(provider, slug), encoding="utf-8")

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Use the correct tool: `python scripts/migrate/port_bundle.py --bundle <provider>` which ports nested subpackages wholesale.
  2. If the subdirectory is junk (scratch code, __pycache__ variants), delete or relocate it first, then re-run consolidate_bundles.py.
  3. If the subpackage is legitimately a separate concern, split it out before consolidating the flat remainder.

Example fix

# before
python scripts/migrate/consolidate_bundles.py --apply agentics
# error: agentics: source has subdirectory/ies ['helpers'] ...

# after
python scripts/migrate/port_bundle.py --bundle agentics --apply
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def is_flat_provider(src: Path) -> bool:
    """consolidate_bundles.move_provider only handles flat layouts."""
    return not any(p.is_dir() and p.name != "__pycache__" for p in src.iterdir())

Prevention

When it happens

Trigger: Running consolidate_bundles.py (dry-run or --apply) on a provider whose directory under COMPONENTS_DIR contains at least one subdirectory other than __pycache__. The guard fires before any mutation, so even a dry-run listing triggers it.

Common situations: Providers that grew helper subpackages over time; leftover experiment folders inside a provider dir; running the mechanical consolidation tool on a layout it was never designed for.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/dc8ee3591cbdf6f0. Report an issue: GitHub.