ComposioHQ/composio · error · UnsafePathComponentError

Refusing to build a path from an unsafe {label}: {value!r}.

Error message

Refusing to build a path from an unsafe {label}: {value!r}. Expected only letters, digits, underscores, and hyphens (pattern {SAFE_COMPONENT_REGEX.pattern}).

What it means

assert_safe_path_component only accepts letters, digits, underscores, and hyphens (^[A-Za-z0-9_-]+$ via fullmatch). Anything else — dots, spaces, unicode, trailing newline — is rejected. fullmatch (not match) is used so 'GMAIL\n' can't sneak a control character past a trailing-$ match.

Source

Thrown at python/composio/utils/safe_path.py:130

            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})."
        )

    if value.upper() in WINDOWS_RESERVED_NAMES:
        raise UnsafePathComponentError(
            f"Refusing to build a path from a reserved device name as {label}: {value!r}"
        )

    return value


def safe_basename(name: str, *, label: str = "filename") -> str:
    """Collapse an untrusted filename to a bare, writable basename.

    Filenames need their own validator: :func:`assert_safe_path_component`
    forbids ``.``, which nearly every real filename contains. This applies the

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Normalize the identifier: strip whitespace and replace disallowed characters with '_'
  2. If the value is user-supplied, enforce the slug pattern at input time
  3. Use safe_basename/secure_basename_join instead when the value is a filename that legitimately contains dots

Example fix

# before
secure_join(root, 'gmail.send_email')
# after
import re
slug = re.sub(r'[^A-Za-z0-9_-]', '_', 'gmail.send_email')
secure_join(root, slug)
Defensive patterns

Strategy: validation

Validate before calling

import re
SAFE = re.compile(r'^[A-Za-z0-9_-]+$')
def is_clean_component(v):
    return isinstance(v, str) and bool(SAFE.fullmatch(v))

Type guard

import re
def is_slug_safe(v: str) -> bool:
    return bool(re.fullmatch(r'[A-Za-z0-9_-]+', v))

Try / catch

from composio.exceptions import UnsafePathComponentError
import re
try:
    p = secure_join(root, slug)
except UnsafePathComponentError:
    p = secure_join(root, re.sub(r'[^A-Za-z0-9_-]', '_', slug))

Prevention

When it happens

Trigger: secure_join(root, 'my.tool'), secure_join(root, 'café'), or any slug with punctuation/whitespace/control characters.

Common situations: Backend tool slugs containing dots or non-ASCII characters; user-supplied names used as directory components; values with trailing newlines from sloppy string handling.

Related errors


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/10e228da74a06e0a. Report an issue: GitHub.