ComposioHQ/composio · error · UnsafePathComponentError
Refusing to write {label} containing invalid Unicode: {name!
Error message
Refusing to write {label} containing invalid Unicode: {name!r} What it means
safe_basename catches UnicodeEncodeError from os.fsencode(basename) — the filename contains characters that cannot be encoded with the filesystem encoding (e.g. surrogates from decoding bytes with errors='replace' on a UTF-8 fs) and is refused rather than crashing at write time.
Source
Thrown at python/composio/utils/safe_path.py:194
if "\x00" in raw_basename:
raise UnsafePathComponentError(
f"Refusing to write {label} containing a NUL byte: {name!r}"
)
if any(ord(char) < 32 or char in '<>:"|?*' for char in raw_basename):
raise UnsafePathComponentError(
f"Refusing to write {label} containing characters reserved by "
f"Windows: {name!r}"
)
if raw_basename.endswith((" ", ".")):
raise UnsafePathComponentError(
f"Refusing to write {label} ending in a space or dot: {name!r}"
)
basename = raw_basename.strip()
try:
encoded_length = len(os.fsencode(basename))
except UnicodeEncodeError as e:
raise UnsafePathComponentError(
f"Refusing to write {label} containing invalid Unicode: {name!r}"
) from e
if encoded_length > MAX_COMPONENT_LENGTH:
raise UnsafePathComponentError(
f"Refusing to write {label} longer than {MAX_COMPONENT_LENGTH} bytes: "
f"{basename[:32]!r}... ({encoded_length} bytes)"
)
# Compare everything before the first dot: on Windows `NUL.tar.gz` opens
# the null device just as `NUL` does, so any number of extensions provides
# no protection.
device_name = basename.split(".", 1)[0].rstrip(" ").upper()
if device_name in WINDOWS_RESERVED_NAMES:
raise UnsafePathComponentError(
f"Refusing to write {label} that is a reserved device name: {name!r}"
)
return basename
View on GitHub (pinned to 64b1b85502)
Solutions
- Re-encode lossily: name.encode('utf-8', 'replace').decode('utf-8') to drop unencodable characters
- Ensure the process runs with a UTF-8 filesystem encoding (LANG/LC_ALL, PYTHONUTF8=1)
- Generate an ASCII fallback filename for unencodable input
Example fix
# before
secure_basename_join(base, name)
# after
name = name.encode('utf-8', 'replace').decode('utf-8')
secure_basename_join(base, name) Defensive patterns
Strategy: fallback
Validate before calling
def encodable(v):
try:
os.fsencode(v)
return True
except UnicodeEncodeError:
return False Type guard
import os
def is_fs_encodable(v: str) -> bool:
try:
os.fsencode(v); return True
except UnicodeEncodeError:
return False Try / catch
from composio.exceptions import UnsafePathComponentError
try:
p = secure_basename_join(base, name)
except UnsafePathComponentError:
p = secure_basename_join(base, name.encode('utf-8','replace').decode('utf-8')) Prevention
- Run with UTF-8 filesystem encoding (PYTHONUTF8=1)
- Normalize surrogate-containing strings with errors='replace' before download
When it happens
Trigger: secure_basename_join(base, name) where name contains lone surrogate code points (\udcXX) — typical when arbitrary bytes were decoded with surrogateescape and the locale/filesystem encoding can't represent them.
Common situations: See trigger scenarios.
Related errors
- Refusing to write {label} containing characters reserved by
- Refusing to write {label} ending in a space or dot: {name!r}
- 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}
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/d063afd8436c5d18.
Report an issue: GitHub.