Jackett/Jackett · error · Exception
Download links not found. Make sure you can download from th
Error message
Download links not found. Make sure you can download from the website.
What it means
Thrown during FunFile.PerformQuery while iterating search-result rows. Each row (matched by the selector 'table.mainframe table[cellpadding="2"] > tbody > tr:has(td.row3)') is expected to contain an anchor with an href starting with 'download.php'. If that anchor is missing on any row, the indexer aborts the entire parse with this message. This is a scraper-fragility error: it fires when the site's HTML markup does not match the indexer's assumptions.
Source
Thrown at src/Jackett.Common/Indexers/Definitions/FunFile.cs:209
if (results.IsRedirect) // re-login
{
await ApplyConfiguration(null);
results = await RequestWithCookiesAndRetryAsync(searchUrl);
}
char[] delimiters = { ',', ' ', '/', ')', '(', '.', ';', '[', ']', '"', '|', ':' };
try
{
var parser = new HtmlParser();
using var dom = parser.ParseDocument(results.ContentString);
var rows = dom.QuerySelectorAll("table.mainframe table[cellpadding=\"2\"] > tbody > tr:has(td.row3)");
foreach (var row in rows)
{
var qDownloadLink = row.QuerySelector("a[href^=\"download.php\"]");
if (qDownloadLink == null)
throw new Exception("Download links not found. Make sure you can download from the website.");
var link = new Uri(SiteLink + qDownloadLink.GetAttribute("href"));
var qDetailsLink = row.QuerySelector("a[href^=\"details.php?id=\"]");
var title = qDetailsLink?.GetAttribute("title")?.Trim();
var details = new Uri(SiteLink + qDetailsLink?.GetAttribute("href")?.Replace("&hit=1", ""));
var categoryLink = row.QuerySelector("a[href^=\"browse.php?cat=\"]")?.GetAttribute("href");
var cat = ParseUtil.GetArgumentFromQueryString(categoryLink, "cat");
var seeders = ParseUtil.CoerceInt(row.Children[9].TextContent);
var leechers = ParseUtil.CoerceInt(row.Children[10].TextContent);
var release = new ReleaseInfo
{
Guid = link,
Link = link,
Details = details,View on GitHub (pinned to adff194147)
Solutions
- Open the FunFile search page in a browser and confirm download links are present on result rows.
- Check if the FunFile site was recently redesigned; if so, the indexer selector needs updating.
- Ensure the configured account has download permissions for all categories being searched.
- Skip rows missing the link instead of throwing, so a single bad row does not kill the whole query.
- Report the HTML change to the Jackett maintainers with a sample of the page source.
Example fix
// before
var qDownloadLink = row.QuerySelector("a[href^=\"download.php\"]");
if (qDownloadLink == null)
throw new Exception("Download links not found. Make sure you can download from the website.");
// after - skip rows without a link
var qDownloadLink = row.QuerySelector("a[href^=\"download.php\"]");
if (qDownloadLink == null)
continue; Defensive patterns
Strategy: try-catch
Validate before calling
// Before parsing, confirm results page actually has download rows
var rows = dom.QuerySelectorAll("table.mainframe table[cellpadding=\"2\"] > tbody > tr:has(td.row3)");
if (!rows.Any(r => r.QuerySelector("a[href^=\"download.php\"]") != null))
logger.Warn("No downloadable rows found — site layout may have changed."); Try / catch
try
{
var releases = await indexer.PerformQuery(query);
}
catch (Exception ex) when (ex.Message.Contains("Download links not found"))
{
// Scraper mismatch — FunFile HTML changed or account lacks download rights
logger.Error("FunFile parse failure: {Message}", ex.Message);
// Do not retry blindly; the selector needs updating
} Prevention
- Confirm the FunFile account has download permissions for searched categories.
- Periodically verify FunFile has not redesigned its torrent table.
- Report persistent parse failures to Jackett maintainers with page source.
- Do not retry on this error — it indicates a structural mismatch, not a transient issue.
When it happens
Trigger: A matched table row has no download link anchor — because the torrent was deleted, the user lacks download permission for that torrent, or FunFile changed its table/column HTML layout so rows match but links moved or were renamed.
Common situations: FunFile pushes a UI redesign that renames download.php links or wraps them in JavaScript; a low-seed/dead torrent row renders without a download button; the user's account class lacks download rights for certain categories.
Related errors
- errorMessage ?? "Login failed."
- Time zone: {time_zone} is not defined.
- Parse error
- Error parsing category!
- Invalid response from AvistaZ, the response is not valid JSO
AI-assisted analysis of Jackett/Jackett@adff194147 (2026-08-13).
Data as JSON: /api/errors/c919d34798837c98.
Report an issue: GitHub.