{"record":{"id":"dc8ee3591cbdf6f0","repo":"langflow-ai/langflow","slug":"provider-source-has-subdirectory-ies-subdirs","errorCode":null,"errorMessage":"{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.","messagePattern":"(.+?): source has subdirectory/ies (.+?) that move_provider does not relocate \\(it copies only top-level \\*\\.py modules\\)\\. Use port_bundle\\.py, which handles nested subpackages, instead\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/migrate/consolidate_bundles.py","lineNumber":297,"sourceCode":"        msg = f\"provider directory not found: {src}\"\n        raise SystemExit(msg)\n    if dst.exists():\n        msg = f\"destination already exists (already consolidated?): {dst}\"\n        raise SystemExit(msg)\n\n    # move_provider relocates only top-level ``*.py`` modules (see the glob\n    # below) but rmtree's the whole source tree.  A provider with a subpackage\n    # would have its subdir silently destroyed -- never copied to the bundle and\n    # never migration-mapped.  Refuse rather than half-move; port_bundle.py is\n    # the tool for nested layouts.\n    subdirs = sorted(p.name for p in src.iterdir() if p.is_dir() and p.name != \"__pycache__\")\n    if subdirs:\n        msg = (\n            f\"{provider}: source has subdirectory/ies {subdirs} that move_provider does not \"\n            \"relocate (it copies only top-level *.py modules). Use port_bundle.py, which \"\n            \"handles nested subpackages, instead.\"\n        )\n        raise SystemExit(msg)\n\n    classes = discover_component_classes(src)\n    py_files = sorted(src.glob(\"*.py\"))\n    print(f\"  {provider}: {len(py_files)} file(s), {len(classes)} component class(es) -> {dst.relative_to(REPO_ROOT)}\")\n    for module_stem, class_name in classes:\n        print(f\"      {module_stem}.{class_name} -> ext:{slug}:{class_name}@official\")\n\n    if not apply:\n        return classes\n\n    dst.mkdir(parents=True)\n    for py in py_files:\n        content = _rewrite_self_imports(py.read_text(encoding=\"utf-8\"), provider, slug)\n        (dst / py.name).write_text(content, encoding=\"utf-8\")\n    # Remove the moved source, then replace the in-tree dir with a one-file shim.\n    shutil.rmtree(src)\n    src.mkdir()\n    (src / \"__init__.py\").write_text(_shim_source(provider, slug), encoding=\"utf-8\")","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/scripts/migrate/consolidate_bundles.py#L279-L315","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the correct tool: `python scripts/migrate/port_bundle.py --bundle <provider>` which ports nested subpackages wholesale.","If the subdirectory is junk (scratch code, __pycache__ variants), delete or relocate it first, then re-run consolidate_bundles.py.","If the subpackage is legitimately a separate concern, split it out before consolidating the flat remainder."],"exampleFix":"# before\npython scripts/migrate/consolidate_bundles.py --apply agentics\n# error: agentics: source has subdirectory/ies ['helpers'] ...\n\n# after\npython scripts/migrate/port_bundle.py --bundle agentics --apply","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef is_flat_provider(src: Path) -> bool:\n    \"\"\"consolidate_bundles.move_provider only handles flat layouts.\"\"\"\n    return not any(p.is_dir() and p.name != \"__pycache__\" for p in src.iterdir())","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check for subpackages before choosing the tool: flat -> consolidate_bundles.py, nested -> port_bundle.py.","Never bypass this guard by deleting subdirectories to force the mechanical move — port them instead.","The guard exists because the move rmtree's the source; ignoring it loses the subpackage permanently."],"tags":["migration","data-loss-prevention","packaging","cli"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}