ComposioHQ/composio · error · ValidationError

{context}: slug must not start with "LOCAL_" — this prefix i

Error message

{context}: slug must not start with "LOCAL_" — this prefix is reserved for internal routing.

What it means

Raised when a custom tool or toolkit slug starts with LOCAL_ (case-insensitive). Composio prefixes internally-routed local tools with LOCAL_, so user slugs in that namespace would collide with the routing layer.

Source

Thrown at python/composio/core/models/custom_tool.py:94

# ────────────────────────────────────────────────────────────────
# Slug validation helpers
# ────────────────────────────────────────────────────────────────


def _validate_slug(slug: str, context: str) -> str:
    """Validate a custom tool or toolkit slug."""
    if not slug:
        raise ValidationError(f"{context}: slug is required")

    if not SLUG_REGEX.match(slug):
        raise ValidationError(
            f"{context}: slug must only contain alphanumeric characters, "
            f"underscores, and hyphens"
        )

    upper = slug.upper()
    if upper.startswith("LOCAL_"):
        raise ValidationError(
            f'{context}: slug must not start with "LOCAL_" — '
            f"this prefix is reserved for internal routing."
        )
    if upper.startswith("COMPOSIO_"):
        raise ValidationError(
            f'{context}: slug must not start with "COMPOSIO_" — '
            f"this prefix is reserved for Composio meta tools."
        )

    return slug


def _compute_final_slug_length(tool_slug: str, toolkit_slug: t.Optional[str]) -> int:
    """Compute the final slug length: LOCAL_[TOOLKIT_]SLUG."""
    length = len(LOCAL_TOOL_PREFIX) + len(tool_slug)
    if toolkit_slug:
        length += len(toolkit_slug) + 1  # +1 for underscore separator
    return length

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Rename the slug to drop the LOCAL_ prefix, e.g. 'local_search' -> 'search' or 'mylocal_search'
  2. Use your own namespace prefix like 'acme_' or 'team_' for grouping

Example fix

# before
Tool(slug="local_file_reader", ...)

# after
Tool(slug="file_reader", ...)  # or "my_file_reader"
Defensive patterns

Strategy: validation

Validate before calling

def ensure_prefix(slug: str) -> str:
    if slug.upper().startswith(("LOCAL_", "COMPOSIO_")):
        return "usr_" + slug
    return slug

Type guard

def has_reserved_prefix(slug: str) -> bool:
    return slug.upper().startswith(("LOCAL_", "COMPOSIO_"))

Try / catch

try:
    Tool(slug=slug, ...)
except ValidationError:
    Tool(slug="app_" + slug, ...)

Prevention

When it happens

Trigger: Naming a custom tool slug like 'local_search' or 'LOCAL_TOOL_X' via Tool(...) or a toolkit with slug starting with 'local_'.

Common situations: Developers prefixing their own tools with local_ thinking it groups them; copying internal Composio examples; naming tools for local-file operations like local_fs_read.

Related errors


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