{"record":{"id":"054a8b338575b5ae","repo":"ComposioHQ/composio","slug":"failed-to-fetch-file-from-url-sanitize-url-for","errorCode":null,"errorMessage":"Failed to fetch file from URL: {_sanitize_url_for_logging(url)}. Error: {e}","messagePattern":"Failed to fetch file from URL: (.+?)\\. Error: (.+?)","errorType":"exception","errorClass":"ErrorUploadingFile","httpStatus":null,"severity":"error","filePath":"python/composio/core/models/_files.py","lineNumber":416,"sourceCode":"\n    Raises:\n        ResponseTooLargeError: If response exceeds max_size\n        ErrorUploadingFile: If fetch fails for other reasons\n    \"\"\"\n    # `safe_get` validates the target, connects to the address it validated\n    # (so DNS cannot rebind between the two), and never follows redirects.\n    try:\n        response = safe_get(\n            url,\n            stream=True,  # Enable streaming for size limiting\n            timeout=(_CONNECT_TIMEOUT, _READ_TIMEOUT),\n        )\n    except requests.exceptions.Timeout:\n        raise ErrorUploadingFile(\n            f\"Request timed out fetching URL: {_sanitize_url_for_logging(url)}\"\n        )\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}\"","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/core/models/_files.py#L398-L434","documentation":"The legacy top-level preload mechanism received a string instead of a list. preload.tools must be a list of Composio tool slugs or the literal 'all'; custom tools are preloaded by setting preload=True on the tool/toolkit definition, not via preload.tools.","triggerScenarios":"Passing preload_tools='my_tool' (a bare string) to the SDK path that calls assert_no_custom_tool_slugs_in_preload via _prepare_inline_custom_tools, e.g. composio.use(..., preload={'tools': 'SOME_TOOL'}) or an equivalent string preload argument.","commonSituations":"Migrating from an older API that accepted a single slug string; writing preload='all' in lowercase or a single slug where a list was expected; copy-pasting a slug where a list belongs.","solutions":["Wrap the slug in a list: preload=['my_tool']","Use the literal 'all' (PRELOAD_TOOLS_ALL) only if you truly want everything","Set preload=True on the CustomTool/Toolkit definition instead of using top-level preload for custom tools"],"exampleFix":"# before\ncomposio.use(toolkits=['github'], preload_tools='GITHUB_CREATE_ISSUE')\n# after\ncomposio.use(toolkits=['github'], preload_tools=['GITHUB_CREATE_ISSUE'])","handlingStrategy":"type-guard","validationCode":"if isinstance(preload_tools, str):\n    preload_tools = [preload_tools] if preload_tools != 'all' else 'all'\ncomposio.use(toolkits=toolkits, preload_tools=preload_tools)","typeGuard":"def is_valid_preload(value) -> bool:\n    if value is None or value == 'all':\n        return True\n    return isinstance(value, list) and all(isinstance(s, str) for s in value)","tryCatchPattern":"try:\n    composio.use(toolkits=toolkits, preload_tools=preload)\nexcept ValidationError as e:\n    if 'preload.tools must be a list' in str(e):\n        composio.use(toolkits=toolkits, preload_tools=[preload])\n    else:\n        raise","preventionTips":["Always pass preload.tools as a list of slugs or the literal 'all'","Use preload=True on custom tool/toolkit definitions instead of top-level preload for custom tools"],"tags":["python","custom-tools","preload","validation","legacy-api"],"backgroundTag":"invalid-argument-type","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}