{"record":{"id":"e51476c59a0c22a1","repo":"langflow-ai/langflow","slug":"err","errorCode":null,"errorMessage":"err","messagePattern":"err","errorType":"validation","errorClass":"UserComponentError","httpStatus":null,"severity":"error","filePath":"src/backend/base/langflow/agentic/services/user_components.py","lineNumber":222,"sourceCode":"# ---------------------------------------------------------------------------\n# internals\n# ---------------------------------------------------------------------------\n\n\ndef _validate_class_name(class_name: str) -> None:\n    if not class_name:\n        msg = \"class_name must be a non-empty string\"\n        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\"))","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/agentic/services/user_components.py#L204-L240","documentation":"Raised by _validate_class_name when _check_windows_portability(class_name) returns an error string (walrus assignment). This shared filesystem-portability guard rejects names containing NUL bytes, path separators, dotdot sequences, control characters, Windows-forbidden punctuation, and trailing dots/spaces — anything that would be unsafe as an on-disk file name under <sandbox>/.components/<ClassName>.py. It fires before the CamelCase regex check, and the message is the guard's own specific text.","triggerScenarios":"Calling register_user_component(user_id=..., class_name=..., code=...) with a class_name containing '/', '\\\\', '..', a control char, a trailing dot/space, or other Windows-forbidden punctuation (e.g. 'Foo:Bar', 'My/Component', 'Foo ').","commonSituations":"An LLM-generated component name embedding a path or namespace ('Tools.Parser'), copy-pasted names with invisible control characters or trailing whitespace, prompt-injection attempts trying to escape the .components directory with dotdot.","solutions":["Strip the class name to a plain CamelCase identifier: letters, digits, underscores, leading uppercase letter.","Remove path separators, dots, colons and any whitespace from the name before registering.","If the name came from model output, regenerate the component with an explicit naming instruction in the prompt."],"exampleFix":"# before\nregister_user_component(user_id=uid, class_name=\"Tools.Parser\", code=src)\n\n# after\nregister_user_component(user_id=uid, class_name=\"ToolsParser\", code=src)","handlingStrategy":"validation","validationCode":"import re\nSAFE_CLASS_RE = re.compile(r\"^[A-Z][A-Za-z0-9_]*$\")\nRESERVED = {\"CON\",\"PRN\",\"AUX\",\"NUL\", *(f\"COM{i}\" for i in range(1,10)), *(f\"LPT{i}\" for i in range(1,10))}\n\ndef is_portable_class_name(name: str) -> bool:\n    return (\n        0 < len(name) <= 64\n        and SAFE_CLASS_RE.fullmatch(name) is not None\n        and name.upper() not in RESERVED\n        and name == name.strip()\n    )","typeGuard":"def is_valid_class_name(name: str | None) -> TypeGuard[str]:\n    return isinstance(name, str) and is_portable_class_name(name)","tryCatchPattern":"from langflow.agentic.services.user_components import UserComponentError\ntry:\n    register_user_component(user_id=uid, class_name=name, code=src)\nexcept UserComponentError as e:\n    # single boundary type: all input refusals land here\n    report_to_generator(str(e))","preventionTips":["Validate names client-side with the same ^[A-Z][A-Za-z0-9_]*$ rule before calling.","Instruct the generating model: 'class name must be CamelCase, uppercase first letter, no punctuation'.","Catch UserComponentError once at the boundary — every refusal is that single class."],"tags":["validation","filesystem-portability","user-components","windows"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}