{"record":{"id":"98a5ea773f441e8d","repo":"langflow-ai/langflow","slug":"could-not-extract-class-name-from-code","errorCode":null,"errorMessage":"Could not extract class name from code","messagePattern":"Could not extract class name from code","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/backend/base/langflow/agentic/helpers/validation.py","lineNumber":334,"sourceCode":"\n    Security: This function MUST NOT execute the code via exec() or eval().\n    All validation is performed via AST parsing and compile() checks.\n    The full runtime validation happens when the component is loaded into a flow.\n\n    Checks performed:\n    1. Syntax validity (ast.parse + compile)\n    2. Class name extraction\n    3. Overlapping input/output names\n    4. Output methods have return statements with values\n    5. No reserved output names/methods that would collide with the\n       synthetic Tool sentinel (``component_as_tool`` / ``to_toolkit``).\n    \"\"\"\n    class_name = _safe_extract_class_name(code)\n\n    try:\n        if class_name is None:\n            msg = \"Could not extract class name from code\"\n            raise ValueError(msg)\n\n        tree = ast.parse(code)\n        compile(ast.Module(body=tree.body, type_ignores=[]), \"<string>\", \"exec\")\n\n        input_names, output_names = _extract_io_names(tree, class_name)\n        overlap = input_names & output_names\n        if overlap:\n            msg = f\"Inputs and outputs have overlapping names: {overlap}\"\n            raise ValueError(msg)\n\n        if _RESERVED_OUTPUT_NAME in output_names:\n            return ValidationResult(\n                is_valid=False,\n                code=code,\n                error=(\n                    f\"Output name {_RESERVED_OUTPUT_NAME!r} is reserved by Langflow for the \"\n                    \"synthetic Tool sentinel that the wiring layer auto-generates when a \"\n                    \"component is flipped to Tool Mode. Declaring it on your own Output \"","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/agentic/helpers/validation.py#L316-L352","documentation":"Thrown by validate_custom_component_code (wrapped into HTTP 400 as CustomComponentValidationError by the flow executor) when _safe_extract_class_name cannot find an extractable top-level class definition in the submitted custom component code. The validator needs the class name to find its inputs/outputs, so code without a recognizable class declaration fails immediately.","triggerScenarios":"POST to an agentic execute/assist endpoint whose flow JSON contains a CustomComponent whose code has no class statement, only commented-out or string-embedded class code, nested/indented class definitions, or syntax so broken the safe extractor bails (returns None rather than raising).","commonSituations":"LLM-generated component code that wraps the class in a function or triple-quoted string; user pasted only imports and helper functions; mixed tab/space indentation hiding the class from the extractor; a .py flow file edited by hand and truncated.","solutions":["Ensure the code defines exactly one top-level class inheriting from Component (or similar), e.g. 'class MyTool(Component):', at column 0.","Remove wrapping — the class must not live inside a function, if-block, or string literal.","Re-indent the file with consistent 4-space indentation so the AST-level extractor can see the class.","Validate locally with ast.parse / the same validation helper before sending the flow."],"exampleFix":"# before\ndef build():\n    class MyTool(Component):  # nested -> extractor returns None\n        ...\n# after\nclass MyTool(Component):  # top-level\n    ...","handlingStrategy":"validation","validationCode":"import ast\n\ndef has_top_level_class(code: str) -> bool:\n    try:\n        return any(isinstance(n, ast.ClassDef) and n.col_offset == 0 for n in ast.parse(code).body)\n    except SyntaxError:\n        return False\n\nassert has_top_level_class(component_code), 'component must define a top-level class'","typeGuard":"const looksLikeComponent = (code: string): boolean =>\n  /^class\\s+\\w+\\s*\\(/m.test(code) && !/^\\s+class\\s/m.test(code.split(/^class/m)[0] + 'class');","tryCatchPattern":"Catch the 400 from the execute endpoint and surface detail verbatim to the flow author; block deployment until the component defines a top-level class.","preventionTips":["Always define exactly one top-level class inheriting Component in custom component code.","Validate generated code with ast.parse before saving it into a flow.","Never wrap component classes in functions, conditionals, or strings."],"tags":["agentic","custom-component","validation","ast","http-400"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}