{"record":{"id":"e4522b0f659d2d4f","repo":"langflow-ai/langflow","slug":"flow-module-must-define-get-graph-function-f","errorCode":null,"errorMessage":"Flow module must define 'get_graph()' function: {flow_path}","messagePattern":"Flow module must define 'get_graph\\(\\)' function: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"src/backend/base/langflow/agentic/services/helpers/flow_loader.py","lineNumber":161,"sourceCode":"        with _temporary_sys_path(str(flow_path.parent)):\n            spec.loader.exec_module(module)\n    except Exception as e:\n        if module_name in sys.modules:\n            del sys.modules[module_name]\n        logger.error(f\"Error loading Python flow module: {e}\")\n        raise HTTPException(status_code=500, detail=f\"Error loading flow module: {e}\") from e\n\n    if not hasattr(module, \"get_graph\"):\n        # Fallback: check for 'graph' variable for backward compatibility\n        if hasattr(module, \"graph\"):\n            graph = module.graph\n            validate_flow_for_current_settings(graph)\n            if module_name in sys.modules:\n                del sys.modules[module_name]\n            return graph\n        if module_name in sys.modules:\n            del sys.modules[module_name]\n        raise HTTPException(status_code=500, detail=f\"Flow module must define 'get_graph()' function: {flow_path}\")\n\n    get_graph_func = module.get_graph\n\n    # Build kwargs for get_graph based on what it accepts\n    sig = inspect.signature(get_graph_func)\n    kwargs = {}\n    if \"provider\" in sig.parameters and provider:\n        kwargs[\"provider\"] = provider\n    if \"model_name\" in sig.parameters and model_name:\n        kwargs[\"model_name\"] = model_name\n    if \"api_key_var\" in sig.parameters and api_key_var:\n        kwargs[\"api_key_var\"] = api_key_var\n    # Python flows never pass through the JSON-side inject_iterations_into_flow,\n    # so the runtime step budget must be forwarded to get_graph explicitly.\n    raw_iterations = (provider_vars or {}).get(\"ITERATIONS_LIMIT\")\n    if \"iterations_limit\" in sig.parameters and raw_iterations not in (None, \"\"):\n        with suppress(TypeError, ValueError):\n            kwargs[\"iterations_limit\"] = int(raw_iterations)","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/agentic/services/helpers/flow_loader.py#L143-L179","documentation":"Raised when flow_loader dynamically imports a Python flow module (.py file) but the module exposes neither a get_graph() function nor a module-level graph variable. Langflow requires one of these as the entry point to materialize a runnable graph. It surfaces as HTTPException 500 from the flow-loading endpoint.","triggerScenarios":"Calling the agentic flow-loader endpoint with a flow_path pointing at a Python file whose module defines neither 'get_graph' nor 'graph' (e.g. only helper functions, or the graph factory is named differently like build_graph()). The module is imported, inspected with hasattr for both symbols, and rejected when both checks fail.","commonSituations":"Migrating flows written for an older loader that expected a different factory name; typos in the function name (getGraph, get_graph_async); a module that conditionally defines get_graph only under __main__; picking the wrong file out of a multi-file flow project.","solutions":["Add a module-level def get_graph() -> Graph: that builds and returns the flow's Graph object.","Alternatively define a module-level graph variable for backward compatibility (the loader accepts it as a fallback).","Check for a typo: the loader matches the exact names 'get_graph' and 'graph'.","Verify you pointed flow_path at the entry file of the flow, not a helper module."],"exampleFix":"# before\n# my_flow.py\ndef build_graph():\n    return Graph(...)\n\n# after\n# my_flow.py\ndef get_graph():\n    return Graph(...)","handlingStrategy":"validation","validationCode":"import importlib.util\n\ndef flow_module_is_loadable(flow_path: str) -> bool:\n    spec = importlib.util.spec_from_file_location(\"_probe\", flow_path)\n    if spec is None or spec.loader is None:\n        return False\n    mod = importlib.util.module_from_spec(spec)\n    try:\n        spec.loader.exec_module(mod)\n    except Exception:\n        return False\n    return hasattr(mod, \"get_graph\") or hasattr(mod, \"graph\")","typeGuard":"def has_graph_entrypoint(module) -> TypeGuard[Any]:\n    return hasattr(module, \"get_graph\") or hasattr(module, \"graph\")","tryCatchPattern":"try:\n    graph = load_flow_module(flow_path)\nexcept HTTPException as e:\n    if \"must define 'get_graph()'\" in e.detail:\n        raise ValueError(f\"{flow_path} lacks get_graph()/graph\") from e\n    raise","preventionTips":["Standardize every Python flow on a module-level get_graph() factory.","Lint flow files in CI with a check that the module exposes get_graph or graph.","Never rename the factory without a loader-compatibility shim (keep a graph variable fallback)."],"tags":["flow-loader","dynamic-import","get-graph","langflow-agentic"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}