{"record":{"id":"d08e24289c445f37","repo":"langflow-ai/langflow","slug":"class-name-must-be-a-camelcase-identifier-letters","errorCode":null,"errorMessage":"class_name must be a CamelCase identifier (letters/digits/underscores, leading uppercase). Got: {class_name!r}","messagePattern":"class_name must be a CamelCase identifier \\(letters/digits/underscores, leading uppercase\\)\\. Got: (.+?)","errorType":"validation","errorClass":"UserComponentError","httpStatus":null,"severity":"error","filePath":"src/backend/base/langflow/agentic/services/user_components.py","lineNumber":230,"sourceCode":"        raise UserComponentError(msg)\n    # Windows-portability path-length cap. Checked BEFORE other rules so\n    # the error message is specific and the rest of the validator never\n    # has to reason about pathological inputs.\n    if len(class_name) > MAX_CLASS_NAME_LENGTH:\n        msg = f\"class_name length {len(class_name)} exceeds max {MAX_CLASS_NAME_LENGTH} (Windows MAX_PATH safeguard)\"\n        raise UserComponentError(msg)\n    # Filesystem-portability guard (rejects NUL, Windows-forbidden punct,\n    # path separators, dotdot, control chars, trailing dot/space, etc.).\n    if err := _check_windows_portability(class_name):\n        raise UserComponentError(err)\n    # Reject `.`, `..`, leading dots, leading underscores, dunders, and\n    # anything that isn't a valid CamelCase identifier.\n    if not _CLASS_NAME_RE.fullmatch(class_name):\n        msg = (\n            f\"class_name must be a CamelCase identifier \"\n            f\"(letters/digits/underscores, leading uppercase). Got: {class_name!r}\"\n        )\n        raise UserComponentError(msg)\n    if class_name.upper() in _WINDOWS_RESERVED_DEVICES:\n        msg = f\"class_name {class_name!r} is a Windows-reserved device name\"\n        raise UserComponentError(msg)\n\n\ndef _validate_code(code: str) -> None:\n    if not code or not code.strip():\n        msg = \"code must be a non-empty string\"\n        raise UserComponentError(msg)\n    encoded_size = len(code.encode(\"utf-8\"))\n    if encoded_size > MAX_COMPONENT_SOURCE_BYTES:\n        msg = f\"code size {encoded_size} bytes exceeds limit of {MAX_COMPONENT_SOURCE_BYTES} bytes\"\n        raise UserComponentError(msg)\n\n\ndef _resolve_components_dir(*, user_id: str | None) -> Path:\n    \"\"\"Resolve and create ``<sandbox>/.components/`` for the given user.\n","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/agentic/services/user_components.py#L212-L248","documentation":"Raised when the proposed component class name fails the strict identifier regex ^[A-Z][A-Za-z0-9_]*$ (fullmatch). Langflow requires the name to be a valid Python identifier starting with an uppercase letter so the same string works both as a class name at import time and as a file stem in the registry overlay. This rejects '.', '..', leading dots/underscores, dunders, snake_case names, and any non-alphanumeric characters.","triggerScenarios":"register_user_component with class_name like 'my_component' (lowercase start), '_Private', '__dunder__', 'Agent-1', or an empty string (empty is caught earlier by the non-empty check, but whitespace-only or malformed names land here).","commonSituations":"Model-generated code using snake_case class names; names prefixed with underscore for 'private' components; hyphenated names copied from a title or filename like 'Data-Loader'.","solutions":["Rename to CamelCase starting with an uppercase letter: 'MyComponent', 'DataLoader', 'Agent1'.","Underscores are allowed but not at the start; convert 'data_loader' to 'DataLoader'.","Update the generation prompt to enforce PEP 8 class naming for the emitted class."],"exampleFix":"# before\nregister_user_component(user_id=uid, class_name=\"data_loader\", code=src)\n\n# after\nregister_user_component(user_id=uid, class_name=\"DataLoader\", code=src)","handlingStrategy":"validation","validationCode":"import re\n_CAMEL = re.compile(r\"^[A-Z][A-Za-z0-9_]*$\")\n\ndef check_class_name(name: str) -> str | None:\n    \"\"\"Return None if valid, else a human-readable problem.\"\"\"\n    if not name:\n        return \"empty\"\n    if not _CAMEL.fullmatch(name):\n        return f\"{name!r} is not CamelCase (uppercase first letter, letters/digits/underscores only)\"\n    return None","typeGuard":"def is_camel_case_class(name: str) -> TypeGuard[str]:\n    return bool(re.fullmatch(r\"[A-Z][A-Za-z0-9_]*\", name or \"\"))","tryCatchPattern":"try:\n    register_user_component(user_id=uid, class_name=name, code=src)\nexcept UserComponentError as e:\n    if \"CamelCase\" in str(e):\n        name = \"\".join(w.capitalize() for w in re.split(r\"[^A-Za-z0-9]+\", name) if w)\n        register_user_component(user_id=uid, class_name=name, code=src)","preventionTips":["Convert snake_case to CamelCase programmatically before registering.","Add a naming rule to the generation prompt and validate the emitted name before the registration hook."],"tags":["validation","class-name","regex","user-components"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}