{"record":{"id":"a045488d77c64545","repo":"unslothai/unsloth","slug":"fail-rate-0-of-the-first-probe-size-image","errorCode":null,"errorMessage":"⚠️ {fail_rate:.0%} of the first {PROBE_SIZE} images failed to download ({probe_fail}/{probe_total}). This dataset has too many broken or unreachable image URLs. Consider using a dataset with embedded images instead.","messagePattern":"⚠️ (.+?) of the first (.+?) images failed to download \\((.+?)/(.+?)\\)\\. This dataset has too many broken or unreachable image URLs\\. Consider using a dataset with embedded images instead\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/utils/datasets/format_conversion.py","lineNumber":556,"sourceCode":"            try:\n                from .llm_assist import llm_generate_dataset_warning\n                friendly = llm_generate_dataset_warning(\n                    issues,\n                    dataset_name = dataset_name,\n                    modality = \"vision\",\n                    column_names = [image_column, text_column],\n                )\n            except Exception:\n                pass\n            msg = friendly or (\n                f\"⚠️ {fail_rate:.0%} of the first {PROBE_SIZE} images failed to download \"\n                f\"({probe_fail}/{probe_total}). \"\n                \"This dataset has too many broken or unreachable image URLs. \"\n                \"Consider using a dataset with embedded images instead.\"\n            )\n            logger.info(msg)\n            _notify(msg)\n            raise ValueError(msg)\n\n        # Estimate time for remaining samples\n        remaining = total - PROBE_SIZE\n        estimated_seconds = remaining / throughput if throughput > 0 else 0\n        eta_str = _format_eta(estimated_seconds)\n\n        info_msg = (\n            f\"Downloading {total:,} images ({num_workers} workers, ~{throughput:.1f} img/s). \"\n            f\"Estimated time: ~{eta_str}\"\n        )\n        if probe_fail > 0:\n            info_msg += f\" | {fail_rate:.0%} broken URLs will be skipped\"\n\n        logger.info(\n            f\"✅ Probe passed: {probe_ok}/{probe_total} ok, {probe_fail} failed ({fail_rate:.0%}), {throughput:.1f} img/s\"\n        )\n        logger.info(f\"⏱️ Estimated time for {total:,} samples: ~{eta_str}\")\n        _notify(info_msg)","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/datasets/format_conversion.py#L538-L574","documentation":"Raised during VLM dataset conversion when the initial probe batch (first PROBE_SIZE images) exceeds the allowed failure rate for image downloads. The probe runs before the bulk download to fail fast instead of wasting hours fetching a mostly-broken dataset. The ValueError carries either an LLM-generated friendly warning or the formatted default message and is surfaced via _notify().","triggerScenarios":"Calling the image-URL-to-VLM conversion path (convert to standard VLM format with an image column of URLs) where >= the threshold fraction of the first PROBE_SIZE URL downloads fail, e.g. dead links, 403s from hotlink protection, DNS failures, or expired signed URLs.","commonSituations":"Training on scraped image-caption datasets (e.g. old ShareGPT/Laion-style dumps) whose hosted images were deleted; datasets behind authentication (HF gated URLs requiring token); proxies/firewalls blocking outbound requests; rate-limited image CDNs returning 429.","solutions":["Use a dataset with embedded images (HF image feature with bytes) instead of URL references, as the message suggests.","Spot-check ~10 URLs from the image column manually (curl) to confirm whether links are dead or blocked by auth/egress.","If URLs need an HF token, ensure HUGGING_FACE_HUB_TOKEN / hf token login is configured before conversion.","If the failure is transient (rate limiting), retry conversion after a delay or with fewer download workers.","Pre-download or rewrite the image column to accessible URLs / local paths, then re-run conversion."],"exampleFix":"# before\nds = load_dataset(\"some/old-url-dataset\")  # image column = dead URLs\nconverted = convert_image_urls_to_vlm(ds)  # raises ValueError\n\n# after\nds = load_dataset(\"some/embedded-image-dataset\")  # images stored as bytes\nconverted = convert_image_urls_to_vlm(ds)  # probe passes","handlingStrategy":"validation","validationCode":"import urllib.request, random\n\ndef probe_image_urls(dataset, image_column, n=10, timeout=10):\n    \"\"\"Return success ratio over a random sample of URLs before conversion.\"\"\"\n    urls = random.sample(list(dataset[image_column]), min(n, len(dataset)))\n    ok = 0\n    for u in urls:\n        if not isinstance(u, str) or not u.startswith((\"http://\", \"https://\")):\n            continue\n        try:\n            req = urllib.request.Request(u, method=\"HEAD\")\n            if urllib.request.urlopen(req, timeout=timeout).status < 400:\n                ok += 1\n        except Exception:\n            pass\n    return ok / max(len(urls), 1)\n\n# before conversion:\n# assert probe_image_urls(ds, \"image_url\") >= 0.8","typeGuard":null,"tryCatchPattern":"try:\n    converted = convert_image_urls_to_vlm(ds)\nexcept ValueError as e:\n    if \"failed to download\" in str(e):\n        # switch to embedded-image dataset or repair URL column\n        ds = load_dataset(embedded_variant)\n        converted = convert_image_urls_to_vlm(ds)\n    else:\n        raise","preventionTips":["Prefer HF datasets with embedded image features (bytes) over URL columns.","Run a 10-URL HEAD probe before launching conversion of large datasets.","Keep HF token configured when datasets link to gated HF-hosted assets.","Pin dataset revisions whose URLs are known-good instead of latest."],"tags":["dataset","vlm","network","image-download","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}