{"record":{"id":"973ccd5182147c7d","repo":"hiyouga/LlamaFactory","slug":"invalid-url-e","errorCode":null,"errorMessage":"Invalid URL: {e}","messagePattern":"Invalid URL: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"src/llamafactory/api/common.py","lineNumber":96,"sourceCode":"        if not hostname:\n            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=\"Invalid URL hostname.\")\n\n        ip_info = socket.getaddrinfo(hostname, parsed_url.port)\n        ip_address_str = ip_info[0][4][0]\n        ip = ipaddress.ip_address(ip_address_str)\n\n        if not ip.is_global:\n            raise HTTPException(\n                status_code=status.HTTP_403_FORBIDDEN,\n                detail=\"Access to private or reserved IP addresses is not allowed.\",\n            )\n\n    except socket.gaierror:\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST, detail=f\"Could not resolve hostname: {parsed_url.hostname}\"\n        )\n    except Exception as e:\n        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f\"Invalid URL: {e}\")\n","sourceCodeStart":78,"sourceCodeEnd":97,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/api/common.py#L78-L97","documentation":"Raised as HTTP 400 by check_ssrf_url's final except: any non-gaierror exception during URL parsing, getaddrinfo, ipaddress parsing, or the is_global check is reported as 'Invalid URL: <exception>'. Common underlying causes: an invalid port (e.g. 'http://host:99999/'), an IP literal ipaddress cannot parse, or other OS-level resolution errors.","triggerScenarios":"URL with out-of-range or non-numeric port (http://example.com:70000/img.png) causing getaddrinfo ValueError; IPv6 literals with bad bracket syntax; other malformed URL edge cases that pass urlparse but break later steps.","commonSituations":"Config-driven port numbers concatenated without validation; IPv6 URLs copied without brackets; exotic proxy-generated URLs.","solutions":["Read the embedded exception text — it names the real problem (port range, address family, etc.).","Validate the URL client-side with new URL() / urllib.parse and a port range check (1-65535).","For IPv6 literals use bracketed form: http://[2001:db8::1]:8080/img.png.","Simplify the URL (drop port, use https default) to isolate the failing component."],"exampleFix":"// before\nurl: 'http://example.com:99999/img.png'\n// after\nurl: 'http://example.com:8080/img.png'","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\ndef url_wellformed(u):\n    p = urlparse(u)\n    if p.scheme not in (\"http\", \"https\") or not p.hostname:\n        return False\n    if p.port is not None and not (1 <= p.port <= 65535):\n        return False\n    return True","typeGuard":"const wellFormedUrl = (u) => { try { const p = new URL(u); return ['http:','https:'].includes(p.protocol) && !!p.hostname && (!p.port || (+p.port <= 65535)); } catch { return false; } };","tryCatchPattern":"catch (e) { if (e.status === 400 && e.detail?.startsWith('Invalid URL:')) { log(e.detail); /* underlying exception names the real issue */ } throw e; }","preventionTips":["Always parse-and-validate URLs client-side, including port range.","Bracket IPv6 literals: http://[::1]:8080/.","Read the embedded exception text — it is the actual cause."],"tags":["security","ssrf","url-validation","http-400"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}