langflow-ai/langflow · error · UserComponentError
class_name {class_name!r} is a Windows-reserved device name
Error message
class_name {class_name!r} is a Windows-reserved device name What it means
Raised when the (uppercased) class name matches a Windows reserved device name: CON, PRN, AUX, NUL, COM1-COM9, LPT1-LPT9. These are valid Python identifiers and pass the CamelCase regex, but Windows refuses to create files with those stems, so the registry guard rejects them explicitly to keep sandboxes cross-platform portable.
Source
Thrown at src/backend/base/langflow/agentic/services/user_components.py:233
# 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"))
if encoded_size > MAX_COMPONENT_SOURCE_BYTES:
msg = f"code size {encoded_size} bytes exceeds limit of {MAX_COMPONENT_SOURCE_BYTES} bytes"
raise UserComponentError(msg)
def _resolve_components_dir(*, user_id: str | None) -> Path:
"""Resolve and create ``<sandbox>/.components/`` for the given user.
Reuses the FS tool's authoritative sandbox resolver so the hash
function, pepper handling, AUTO_LOGIN dispatch, and no-user refusal
stay in one place. The reserved-segment guard does NOT apply here —View on GitHub (pinned to 976ec789d2)
Solutions
- Rename the class to something that is not a DOS device name, e.g. 'AuxHandler' instead of 'Aux'.
- Lengthen or prefix generated names so they can never equal the 20 reserved tokens.
Example fix
# before register_user_component(user_id=uid, class_name="Aux", code=src) # after register_user_component(user_id=uid, class_name="AuxiliaryHelper", code=src)
Defensive patterns
Strategy: validation
Validate before calling
WINDOWS_RESERVED = {"CON","PRN","AUX","NUL", *(f"COM{i}" for i in range(1,10)), *(f"LPT{i}" for i in range(1,10))}
def not_windows_device(name: str) -> bool:
return name.upper() not in WINDOWS_RESERVED Type guard
def is_safe_file_stem(name: str) -> TypeGuard[str]:
return bool(re.fullmatch(r"[A-Z][A-Za-z0-9_]*", name)) and name.upper() not in WINDOWS_RESERVED Try / catch
try:
register_user_component(user_id=uid, class_name=name, code=src)
except UserComponentError as e:
if "Windows-reserved" in str(e):
name += "Component" # CON -> CONComponent
register_user_component(user_id=uid, class_name=name, code=src) Prevention
- Avoid 3-letter device-like names (CON, AUX, NUL, PRN, COMn, LPTn) when naming generated classes.
- Prefer descriptive multi-word class names; they cannot collide with reserved devices.
When it happens
Trigger: register_user_component with class_name 'Con', 'NUL', 'Aux', 'Com1', 'LPT1' etc. — the check is case-insensitive (class_name.upper()).
Common situations: Short generated names colliding with DOS device names ('Aux' is a realistic generator output); deliberate edge-case testing; names like 'Con' from truncating 'Connection'.
Related errors
- err
- 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/619f2f7bde4623a6.
Report an issue: GitHub.