{"record":{"id":"deb9526bd1e9a641","repo":"FujiwaraChoki/MoneyPrinterV2","slug":"affiliate-link-is-invalid-expected-a-full-url-go","errorCode":null,"errorMessage":"Affiliate link is invalid. Expected a full URL, got: {self.affiliate_link}","messagePattern":"Affiliate link is invalid\\. Expected a full URL, got: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/classes/AFM.py","lineNumber":75,"sourceCode":"\n        # Set the profile path\n        self.options.add_argument(\"-profile\")\n        self.options.add_argument(fp_profile_path)\n\n        # Set the service\n        self.service: Service = Service(GeckoDriverManager().install())\n\n        # Initialize the browser\n        self.browser: webdriver.Firefox = webdriver.Firefox(\n            service=self.service, options=self.options\n        )\n\n        # Set the affiliate link\n        self.affiliate_link: str = affiliate_link\n\n        parsed_link = urlparse(self.affiliate_link)\n        if parsed_link.scheme not in [\"http\", \"https\"] or not parsed_link.netloc:\n            raise ValueError(\n                f\"Affiliate link is invalid. Expected a full URL, got: {self.affiliate_link}\"\n            )\n\n        # Set the Twitter account UUID\n        self.account_uuid: str = twitter_account_uuid\n\n        # Set the Twitter account nickname\n        self.account_nickname: str = account_nickname\n\n        # Set the Twitter topic\n        self.topic: str = topic\n\n        # Scrape the product information\n        self.scrape_product_information()\n\n    def scrape_product_information(self) -> None:\n        \"\"\"\n        This method will be used to scrape the product","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/FujiwaraChoki/MoneyPrinterV2/blob/5192af8eca97759f941834b947e3ceb209da0649/src/classes/AFM.py#L57-L93","documentation":"Raised in AFM.__init__ when the affiliate link does not parse as an absolute http(s) URL. The class needs a full URL (scheme + host) to later append tracking parameters, so relative or malformed links are rejected.","triggerScenarios":"Passing affiliate_link like 'example.com/?ref=1' (no scheme), 'ftp://...', a bare path '/ref/123', or an empty/None-coerced string.","commonSituations":"Links scraped or typed without the https:// prefix, links read from a spreadsheet/config that stripped the scheme, or trailing whitespace breaking urlparse.","solutions":["Prepend 'https://' when the scheme is missing","Trim whitespace and validate the link at its source (config/UI) before constructing AFM","Reject non-http(s) schemes like mailto: or ftp: early"],"exampleFix":"// before\nafm = AFM(affiliate_link=\"example.com/?ref=123\", ...)\n\n// after\nlink = affiliate_link.strip()\nif not link.startswith((\"http://\", \"https://\")):\n    link = \"https://\" + link\nafm = AFM(affiliate_link=link, ...)","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\nlink = (affiliate_link or \"\").strip()\nif not link.startswith((\"http://\", \"https://\")):\n    link = \"https://\" + link\nparsed = urlparse(link)\nif parsed.scheme not in (\"http\", \"https\") or not parsed.netloc:\n    raise ValueError(f\"Invalid affiliate link: {link!r}\")","typeGuard":"from urllib.parse import urlparse\n\ndef is_full_http_url(link: str) -> bool:\n    try:\n        p = urlparse((link or \"\").strip())\n    except ValueError:\n        return False\n    return p.scheme in (\"http\", \"https\") and bool(p.netloc)","tryCatchPattern":null,"preventionTips":["Strip whitespace on links sourced from spreadsheets or user input","Auto-prepend https:// for scheme-less links before constructing AFM","Validate links at data-entry time so bad values never reach the constructor"],"tags":["python","validation","url-parsing"],"backgroundTag":"invalid-url-format","analyzedSha":"5192af8eca97759f941834b947e3ceb209da0649","analyzedAt":"2026-08-28T10:31:46.474Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}