{"record":{"id":"51f0f9b031296459","repo":"ComposioHQ/composio","slug":"failed-to-fetch-file-from-url-sanitize-url-for-51f0f9","errorCode":null,"errorMessage":"Failed to fetch file from URL: {_sanitize_url_for_logging(url)}. Status: {response.status_code}","messagePattern":"Failed to fetch file from URL: (.+?)\\. Status: (.+?)","errorType":"exception","errorClass":"ErrorUploadingFile","httpStatus":null,"severity":"error","filePath":"python/composio/core/models/_files.py","lineNumber":432,"sourceCode":"        )\n    except requests.exceptions.RequestException as e:\n        raise ErrorUploadingFile(\n            f\"Failed to fetch file from URL: {_sanitize_url_for_logging(url)}. Error: {e}\"\n        )\n\n    # Reject redirects - require direct URL to resource\n    if response.status_code in (301, 302, 303, 307, 308):\n        location = response.headers.get(\"Location\", \"unknown\")\n        response.close()\n        raise ErrorUploadingFile(\n            f\"URL returned redirect to {_sanitize_url_for_logging(location)}. \"\n            f\"Please provide a direct URL to the file.\"\n        )\n\n    # Check for successful response\n    if not response.ok:\n        response.close()\n        raise ErrorUploadingFile(\n            f\"Failed to fetch file from URL: {_sanitize_url_for_logging(url)}. \"\n            f\"Status: {response.status_code}\"\n        )\n\n    # Check Content-Length header first (early abort for oversized files).\n    # The header is a hint from the remote server: `parse_content_length`\n    # returns None for anything untrustworthy, and the streaming guard below\n    # is the authoritative limit.\n    content_length = parse_content_length(response.headers.get(\"Content-Length\"))\n    if content_length is not None and content_length > max_size:\n        response.close()\n        raise ResponseTooLargeError(\n            f\"File size ({content_length} bytes) exceeds maximum allowed \"\n            f\"size ({max_size} bytes)\"\n        )\n\n    # Stream response with size tracking\n    chunks: t.List[bytes] = []","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/_files.py#L414-L450","documentation":"MCPServer.create was called with an empty or falsy toolkits argument. At least one toolkit configuration (string slug or MCPToolkitConfig) is required to create an MCP server.","triggerScenarios":"Calling server.create(toolkits=[]), server.create(toolkits=None), or passing an empty list/iterable to MCPServer.create in python/composio/core/models/mcp.py.","commonSituations":"Dynamically building the toolkit list and passing an empty result; conditionally filtering toolkits down to nothing; defaulting a config value to an empty list.","solutions":["Pass at least one toolkit slug or MCPToolkitConfig (e.g. ['github'])","Guard before calling: skip server creation when the toolkit list is empty","Fix upstream logic that produces an empty toolkits collection"],"exampleFix":"# before\nmcp = server.create(toolkits=filtered_toolkits)  # may be []\n# after\nif filtered_toolkits:\n    mcp = server.create(toolkits=filtered_toolkits)\nelse:\n    raise ValueError('No toolkits selected for MCP server')","handlingStrategy":"validation","validationCode":"if not toolkits:\n    raise ValueError('Cannot create MCP server with no toolkits')\nmcp = server.create(toolkits=toolkits)","typeGuard":"def has_toolkits(toolkits) -> bool:\n    return bool(toolkits) and len(list(toolkits)) > 0","tryCatchPattern":"try:\n    mcp = server.create(toolkits=toolkits)\nexcept ValidationError as e:\n    if str(e) == 'At least one toolkit configuration is required':\n        raise ValueError(f'Build toolkits list before creating MCP server') from e\n    raise","preventionTips":["Default the toolkits argument to a required non-empty list in your wrapper","Validate dynamically filtered toolkit lists before calling create"],"tags":["python","mcp","toolkit","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}