ComposioHQ/composio · error · UnsafePathComponentError
Refusing to build a path from a {label} longer than {MAX_COM
Error message
Refusing to build a path from a {label} longer than {MAX_COMPONENT_LENGTH} characters: {value[:32]!r}... ({len(value)} characters) What it means
assert_safe_path_component rejects a single path component longer than MAX_COMPONENT_LENGTH (128 characters), keeping components well under the 255-byte filename limit of ext4/APFS/NTFS so a write never fails mid-operation with OSError.
Source
Thrown at python/composio/utils/safe_path.py:116
:raises UnsafePathComponentError: when ``value`` is unsafe.
"""
if not isinstance(value, str) or not value:
raise UnsafePathComponentError(
f"Refusing to build a path from an empty or non-string {label}: {value!r}"
)
# `PureWindowsPath` treats both `/` and `\` as separators, so a single check
# catches `../x` and `..\x` regardless of the host platform. A slug crafted
# for a Windows target must not slip through on a POSIX build machine.
as_windows_path = PureWindowsPath(value)
if len(as_windows_path.parts) != 1 or as_windows_path.anchor:
raise UnsafePathComponentError(
f"Refusing to build a path from a {label} containing path separators "
f"or a drive letter: {value!r}"
)
if len(value) > MAX_COMPONENT_LENGTH:
raise UnsafePathComponentError(
f"Refusing to build a path from a {label} longer than "
f"{MAX_COMPONENT_LENGTH} characters: {value[:32]!r}... "
f"({len(value)} characters)"
)
# `.` and `..` are excluded by the regex (no `.` in the character class),
# as are NUL bytes and every separator. The explicit checks above exist to
# produce a precise error message rather than a generic pattern mismatch.
#
# `fullmatch`, not `match`: in a `match`, `$` also matches just before a
# single trailing newline, so `"GMAIL\n"` would satisfy `^[A-Za-z0-9_-]+$`
# and reach the filesystem with a control character in the name.
if not SAFE_COMPONENT_REGEX.fullmatch(value):
raise UnsafePathComponentError(
f"Refusing to build a path from an unsafe {label}: {value!r}. "
f"Expected only letters, digits, underscores, and hyphens "
f"(pattern {SAFE_COMPONENT_REGEX.pattern})."
)View on GitHub (pinned to 64b1b85502)
Solutions
- Hash or truncate long identifiers before using them as directory names (e.g. sha256 hex of the slug)
- Store the full identifier in a metadata file inside a short-named directory
- Report legitimate catalog slugs that exceed 128 chars
Example fix
# before secure_join(root, very_long_slug) # after import hashlib short = hashlib.sha256(very_long_slug.encode()).hexdigest()[:32] secure_join(root, short)
Defensive patterns
Strategy: validation
Validate before calling
def component_within_limit(v):
return isinstance(v, str) and 0 < len(v) <= 128 Type guard
def is_short_component(v) -> bool:
return isinstance(v, str) and 0 < len(v) <= 128 Try / catch
from composio.exceptions import UnsafePathComponentError
import hashlib
try:
p = secure_join(root, slug)
except UnsafePathComponentError:
p = secure_join(root, hashlib.sha256(slug.encode()).hexdigest()[:32]) Prevention
- Hash long identifiers before using them as directory names
- Keep generated slug length bounded at creation time
When it happens
Trigger: secure_join(root, slug) where slug exceeds 128 chars — e.g. a generated ID, hash, or long tool/action name used as a directory name.
Common situations: Backend-generated composite IDs or namespaced slugs (tool__action__param hashes) used directly as cache/workspace directory names.
Related errors
- Could not determine a home directory to store the Composio c
- Cache directory {directory} is not writable please provide a
- module {__name__!r} has no attribute {name!r}
- Failed to upload to S3: {_sanitize_url_for_logging(url)}. Er
- Failed to upload to S3. Status: {response.status_code}. This
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/716273d6b9a42180.
Report an issue: GitHub.