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
- 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.
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
- 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.
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
- class_name {class_name!r} is a Windows-reserved device name
- class_name must be a CamelCase identifier (letters/digits/un
- code must be a non-empty string
- code size {encoded_size} bytes exceeds limit of {MAX_COMPONE
- Invalid path: {e}
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/e51476c59a0c22a1.
Report an issue: GitHub.