langflow-ai/langflow · error · SystemExit

{src} imports from ``langflow`` -- the bundle is installed a

Error message

{src} imports from ``langflow`` -- the bundle is installed against the public BUNDLE_API surface (lfx), not Langflow internals.  Either rewrite the import or leave the component in-tree.  See src/bundles/PORTING.md § 0.

What it means

Identical guard to error 54, but for top-level provider modules rather than nested subpackage files: port_bundle.py reads every top-level *.py under the in-tree provider dir and refuses the port if any contains 'from langflow'. Bundles are distributed standalone against lfx, so a Langflow-internal import makes the module unportable as-is; the error names the offending file and defers to PORTING.md § 0.

Source

Thrown at scripts/migrate/port_bundle.py:729

                        f"{nested} imports from ``langflow`` -- the bundle is "
                        "installed against the public BUNDLE_API surface (lfx), "
                        "not Langflow internals.  Either rewrite the import or "
                        "leave the component in-tree.  See src/bundles/PORTING.md § 0."
                    )
                    raise SystemExit(msg)
            nested_subdirs.append(src)
            continue
        if not src.is_file() or src.suffix != ".py":
            continue
        text = src.read_text(encoding="utf-8")
        if "from langflow" in text:
            msg = (
                f"{src} imports from ``langflow`` -- the bundle is installed "
                "against the public BUNDLE_API surface (lfx), not Langflow "
                "internals.  Either rewrite the import or leave the component "
                "in-tree.  See src/bundles/PORTING.md § 0."
            )
            raise SystemExit(msg)
        classes = () if src.name == "__init__.py" else _discover_classes(text)
        component_files.append(ComponentFile(path=src, classes=classes))

    if not component_files and not nested_subdirs:
        msg = f"No ``*.py`` files under {in_tree}; nothing to port."
        raise SystemExit(msg)

    if migration_release is not None and not re.fullmatch(r"\d+\.\d+\.\d+", migration_release):
        msg = f"--migration-release {migration_release!r} must be a three-segment SemVer (e.g. 1.10.0)."
        raise SystemExit(msg)

    resolved_display = display_name if display_name is not None else bundle.replace("_", " ").title()

    shared_base = LFX_BASE / bundle
    shared_base_dir = shared_base if shared_base.is_dir() else None

    backend_test_dirs = _discover_backend_test_dirs(bundle)
    ruff_ignores = _discover_ruff_ignores(bundle)

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Rewrite the import in the named file to its lfx counterpart (e.g. langflow.custom -> lfx.custom, langflow.io -> lfx.io, langflow.schema -> lfx.schema).
  2. Grep the whole provider dir first: `grep -rn 'from langflow' <in-tree dir>` to fix all hits in one pass.
  3. Re-run the port; the guard re-checks every file each time.

Example fix

# before (openai/model.py)
from langflow.io import Output, StrInput

# after (openai/model.py)
from lfx.io import Output, StrInput
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def top_level_langflow_imports(provider_dir: Path) -> list[Path]:
    return [
        p for p in sorted(provider_dir.glob("*.py"))
        if "from langflow" in p.read_text(encoding="utf-8")
    ]

Prevention

When it happens

Trigger: Running port_bundle.py on a provider where a top-level module (e.g. <provider>/model.py) still does `from langflow.field_typing import ...` or any other langflow import. Like 54, the detection is a raw substring test on the file text.

Common situations: Pre-lfx-split component code; partially migrated providers where most files were converted but one was missed; false positives from comments containing the phrase.

Related errors


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