{"record":{"id":"906fc77fc91a9c70","repo":"ComposioHQ/composio","slug":"context-slug-must-not-start-with-composio","errorCode":null,"errorMessage":"{context}: slug must not start with \"COMPOSIO_\" — this prefix is reserved for Composio meta tools.","messagePattern":"(.+?): slug must not start with \"COMPOSIO_\" — this prefix is reserved for Composio meta tools\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"python/composio/core/models/custom_tool.py","lineNumber":99,"sourceCode":"def _validate_slug(slug: str, context: str) -> str:\n    \"\"\"Validate a custom tool or toolkit slug.\"\"\"\n    if not slug:\n        raise ValidationError(f\"{context}: slug is required\")\n\n    if not SLUG_REGEX.match(slug):\n        raise ValidationError(\n            f\"{context}: slug must only contain alphanumeric characters, \"\n            f\"underscores, and hyphens\"\n        )\n\n    upper = slug.upper()\n    if upper.startswith(\"LOCAL_\"):\n        raise ValidationError(\n            f'{context}: slug must not start with \"LOCAL_\" — '\n            f\"this prefix is reserved for internal routing.\"\n        )\n    if upper.startswith(\"COMPOSIO_\"):\n        raise ValidationError(\n            f'{context}: slug must not start with \"COMPOSIO_\" — '\n            f\"this prefix is reserved for Composio meta tools.\"\n        )\n\n    return slug\n\n\ndef _compute_final_slug_length(tool_slug: str, toolkit_slug: t.Optional[str]) -> int:\n    \"\"\"Compute the final slug length: LOCAL_[TOOLKIT_]SLUG.\"\"\"\n    length = len(LOCAL_TOOL_PREFIX) + len(tool_slug)\n    if toolkit_slug:\n        length += len(toolkit_slug) + 1  # +1 for underscore separator\n    return length\n\n\ndef _validate_slug_length(\n    tool_slug: str, toolkit_slug: t.Optional[str], context: str\n) -> None:","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/custom_tool.py#L81-L117","documentation":"Raised when a custom tool or toolkit slug starts with COMPOSIO_ (case-insensitive). This prefix is reserved for Composio's meta tools (framework-provided built-ins), so user slugs cannot claim it.","triggerScenarios":"Naming a custom tool slug like 'composio_search' or 'COMPOSIO_META' when creating a Tool or toolkit.","commonSituations":"Wrapping a Composio built-in and prefixing the wrapper with composio_ to indicate origin; teams namespace all tools with a company/tool prefix that happens to be composio_.","solutions":["Rename the slug to remove the COMPOSIO_ prefix, e.g. 'composio_wrapper' -> 'composio_wrapper_tool' is not enough — use a different namespace like 'wrapper_tool'","If wrapping a built-in, name it after the wrapper's purpose, not the vendor"],"exampleFix":"# before\nTool(slug=\"composio_proxy\", ...)\n\n# after\nTool(slug=\"proxy\", ...)  # or \"my_proxy\"","handlingStrategy":"validation","validationCode":"def ensure_prefix(slug: str) -> str:\n    if slug.upper().startswith((\"LOCAL_\", \"COMPOSIO_\")):\n        return \"usr_\" + slug\n    return slug","typeGuard":"def has_reserved_prefix(slug: str) -> bool:\n    return slug.upper().startswith((\"LOCAL_\", \"COMPOSIO_\"))","tryCatchPattern":"try:\n    Tool(slug=slug, ...)\nexcept ValidationError:\n    Tool(slug=\"app_\" + slug, ...)","preventionTips":["Never prefix custom slugs with composio_ or local_","Namespace with your own org/team prefix instead","Test slug validation early when auto-generating many tools"],"tags":["python","custom-tools","reserved-prefix"],"backgroundTag":"reserved-identifier-conflict","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}