langflow-ai/langflow · error · UserComponentError

err

Error message

err

What it means

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.

Source

Thrown at src/backend/base/langflow/agentic/services/user_components.py:222

# ---------------------------------------------------------------------------
# internals
# ---------------------------------------------------------------------------


def _validate_class_name(class_name: str) -> None:
    if not class_name:
        msg = "class_name must be a non-empty string"
        raise UserComponentError(msg)
    # Windows-portability path-length cap. Checked BEFORE other rules so
    # the error message is specific and the rest of the validator never
    # has to reason about pathological inputs.
    if len(class_name) > MAX_CLASS_NAME_LENGTH:
        msg = f"class_name length {len(class_name)} exceeds max {MAX_CLASS_NAME_LENGTH} (Windows MAX_PATH safeguard)"
        raise UserComponentError(msg)
    # Filesystem-portability guard (rejects NUL, Windows-forbidden punct,
    # path separators, dotdot, control chars, trailing dot/space, etc.).
    if err := _check_windows_portability(class_name):
        raise UserComponentError(err)
    # Reject `.`, `..`, leading dots, leading underscores, dunders, and
    # anything that isn't a valid CamelCase identifier.
    if not _CLASS_NAME_RE.fullmatch(class_name):
        msg = (
            f"class_name must be a CamelCase identifier "
            f"(letters/digits/underscores, leading uppercase). Got: {class_name!r}"
        )
        raise UserComponentError(msg)
    if class_name.upper() in _WINDOWS_RESERVED_DEVICES:
        msg = f"class_name {class_name!r} is a Windows-reserved device name"
        raise UserComponentError(msg)


def _validate_code(code: str) -> None:
    if not code or not code.strip():
        msg = "code must be a non-empty string"
        raise UserComponentError(msg)
    encoded_size = len(code.encode("utf-8"))

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Strip the class name to a plain CamelCase identifier: letters, digits, underscores, leading uppercase letter.
  2. Remove path separators, dots, colons and any whitespace from the name before registering.
  3. If the name came from model output, regenerate the component with an explicit naming instruction in the prompt.

Example fix

# before
register_user_component(user_id=uid, class_name="Tools.Parser", code=src)

# after
register_user_component(user_id=uid, class_name="ToolsParser", code=src)
Defensive patterns

Strategy: validation

Validate before calling

import re
SAFE_CLASS_RE = re.compile(r"^[A-Z][A-Za-z0-9_]*$")
RESERVED = {"CON","PRN","AUX","NUL", *(f"COM{i}" for i in range(1,10)), *(f"LPT{i}" for i in range(1,10))}

def is_portable_class_name(name: str) -> bool:
    return (
        0 < len(name) <= 64
        and SAFE_CLASS_RE.fullmatch(name) is not None
        and name.upper() not in RESERVED
        and name == name.strip()
    )

Type guard

def is_valid_class_name(name: str | None) -> TypeGuard[str]:
    return isinstance(name, str) and is_portable_class_name(name)

Try / catch

from langflow.agentic.services.user_components import UserComponentError
try:
    register_user_component(user_id=uid, class_name=name, code=src)
except UserComponentError as e:
    # single boundary type: all input refusals land here
    report_to_generator(str(e))

Prevention

When it happens

Trigger: 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 ').

Common situations: 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.

Related errors


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