ComposioHQ/composio · error · ErrorUploadingFile

Request timed out fetching URL: {_sanitize_url_for_logging(u

Error message

Request timed out fetching URL: {_sanitize_url_for_logging(url)}

What it means

Same duplicate-slug rule as the top-level list, but for tools contributed by toolkits: a toolkit's tool slug collides (case-insensitively) with an already-registered top-level custom tool or a previously processed toolkit's tool.

Source

Thrown at python/composio/core/models/_files.py:412

        max_size: Maximum response size in bytes (default: 100MB)

    Returns:
        Tuple of (filename, content_bytes, mimetype)

    Raises:
        ResponseTooLargeError: If response exceeds max_size
        ErrorUploadingFile: If fetch fails for other reasons
    """
    # `safe_get` validates the target, connects to the address it validated
    # (so DNS cannot rebind between the two), and never follows redirects.
    try:
        response = safe_get(
            url,
            stream=True,  # Enable streaming for size limiting
            timeout=(_CONNECT_TIMEOUT, _READ_TIMEOUT),
        )
    except requests.exceptions.Timeout:
        raise ErrorUploadingFile(
            f"Request timed out fetching URL: {_sanitize_url_for_logging(url)}"
        )
    except requests.exceptions.RequestException as e:
        raise ErrorUploadingFile(
            f"Failed to fetch file from URL: {_sanitize_url_for_logging(url)}. Error: {e}"
        )

    # Reject redirects - require direct URL to resource
    if response.status_code in (301, 302, 303, 307, 308):
        location = response.headers.get("Location", "unknown")
        response.close()
        raise ErrorUploadingFile(
            f"URL returned redirect to {_sanitize_url_for_logging(location)}. "
            f"Please provide a direct URL to the file."
        )

    # Check for successful response
    if not response.ok:

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Rename the colliding tool inside the toolkit (or the toolkit prefix scheme)
  2. Remove the standalone tool that duplicates the toolkit one
  3. Namespace tool slugs per toolkit (e.g. GH_CREATE_ISSUE vs JIRA_CREATE_ISSUE)

Example fix

# before
toolkit_a = Toolkit(slug='a', tools=[CustomTool(slug='CREATE', ...)])
toolkit_b = Toolkit(slug='b', tools=[CustomTool(slug='create', ...)])
# after
toolkit_a = Toolkit(slug='a', tools=[CustomTool(slug='A_CREATE', ...)])
toolkit_b = Toolkit(slug='b', tools=[CustomTool(slug='B_CREATE', ...)])
Defensive patterns

Strategy: validation

Validate before calling

seen = {h.slug.upper() for h in tools}
for tk in toolkits or []:
    for h in tk.tools:
        k = h.slug.upper()
        if k in seen:
            raise ValueError(f'Slug {h.slug} in toolkit {tk.slug} already registered')
        seen.add(k)

Type guard

def no_cross_toolkit_collisions(tools: list, toolkits: list) -> bool:
    seen = {h.slug.upper() for h in tools}
    for tk in toolkits:
        for h in tk.tools:
            if h.slug.upper() in seen:
                return False
            seen.add(h.slug.upper())
    return True

Try / catch

try:
    m = build_custom_tools_map_from_response(tools, toolkits)
except ValidationError as e:
    if 'unique slug' in str(e):
        raise ValueError(f'Toolkit tool collision: {e}') from e
    raise

Prevention

When it happens

Trigger: Passing toolkits to build_custom_tools_map_from_response where tk.tools contains a slug that .upper()-matches a slug already in handles_by_original, via create/use/test_builds_from_response.

Common situations: Two toolkits exposing a common base tool name; a toolkit tool sharing a name with a standalone custom tool; shared helper tool modules imported by multiple toolkits.

Understand the failure class

Related errors


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