{"record":{"id":"5a71caacc13c3b40","repo":"calesthio/OpenMontage","slug":"no-audio-url-found-for-the-selected-track","errorCode":null,"errorMessage":"No audio URL found for the selected track.","messagePattern":"No audio URL found for the selected track\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"tools/audio/pixabay_music.py","lineNumber":327,"sourceCode":"        )\n        seen: set[str] = set()\n        for url in mp3_urls:\n            if url not in seen:\n                seen.add(url)\n                tracks.append({\n                    \"title\": \"Unknown\",\n                    \"audio_url\": url,\n                    \"duration\": None,\n                    \"artist\": \"Unknown\",\n                })\n\n        return tracks\n\n    def _download(self, track: dict, inputs: dict[str, Any]) -> Path:\n        \"\"\"Download an MP3 track to the output path.\"\"\"\n        audio_url = track.get(\"audio_url\")\n        if not audio_url:\n            raise RuntimeError(\"No audio URL found for the selected track.\")\n\n        # Ensure URL is absolute\n        if audio_url.startswith(\"//\"):\n            audio_url = \"https:\" + audio_url\n        elif audio_url.startswith(\"/\"):\n            audio_url = \"https://pixabay.com\" + audio_url\n\n        # Build output path\n        track_title = track.get(\"title\", \"pixabay_music\")\n        safe_title = \"\".join(\n            c if c.isalnum() or c in \"._- \" else \"_\" for c in track_title\n        )\n        default_filename = f\"pixabay_music_{safe_title[:60]}.mp3\"\n        output_path = Path(inputs.get(\"output_path\", default_filename))\n        output_path.parent.mkdir(parents=True, exist_ok=True)\n\n        request = urllib.request.Request(\n            audio_url,","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/audio/pixabay_music.py#L309-L345","documentation":"Raised by PixabayTool._download when the track dict selected for download has no 'audio_url' key. Tracks are harvested by scraping Pixabay search pages, so the URL depends entirely on the page's current HTML/DOM structure. If Pixabay changes markup or the scraper's regex misses, tracks enter the list with audio_url=None and download is impossible.","triggerScenarios":"Calling the pixabay_music tool with a track index/selection whose scraped entry lacked a parseable audio URL; Pixabay serving a different HTML layout (A/B test, redesign, bot detection page) so the extraction in _search returns {'title': 'Unknown', 'audio_url': None} entries.","commonSituations":"Pixabay site redesign or CDN/anti-bot interstitial breaking the scraper; selecting a track from a stale cached result list; running the tool in a region where Pixabay serves different markup.","solutions":["Re-run the search step so track metadata is freshly scraped, then pick a track whose audio_url is populated.","Log or inspect the scraped track list (titles like 'Unknown' and missing durations are tell-tale signs the scraper broke) and choose another entry.","If all entries lack audio_url, the Pixabay page structure changed: update the extraction logic in the _search method to the new markup.","Fall back to a different music provider tool (e.g. suno_music or the HeyGen audio library) until the scraper is fixed."],"exampleFix":"// before\ntrack = tracks[inputs[\"track_index\"]]\npath = tool._download(track, inputs)  # RuntimeError: no audio_url\n\n// after\ntrack = tracks[inputs[\"track_index\"]]\nif not track.get(\"audio_url\"):\n    tracks = [t for t in tracks if t.get(\"audio_url\")]\n    if not tracks:\n        raise RuntimeError(\"Pixabay scraper returned no playable tracks; page layout likely changed\")\n    track = tracks[0]\npath = tool._download(track, inputs)","handlingStrategy":"validation","validationCode":"track = tracks[selection]\nif not track.get(\"audio_url\"):\n    playable = [i for i, t in enumerate(tracks) if t.get(\"audio_url\")]\n    if not playable:\n        raise RuntimeError(\"Pixabay scraper returned no playable tracks\")\n    selection = playable[0]\n    track = tracks[selection]","typeGuard":"def has_audio_url(track: dict) -> bool:\n    url = track.get(\"audio_url\")\n    return isinstance(url, str) and url.startswith((\"http\", \"//\", \"/\"))","tryCatchPattern":"try:\n    path = tool._download(track, inputs)\nexcept RuntimeError as e:\n    if \"No audio URL\" in str(e):\n        # re-search and pick a track with a populated audio_url\n        raise","preventionTips":["Filter scraped track lists on audio_url before presenting choices to users","Treat 'Unknown' titles and null durations as scraper-breakage signals and re-search"],"tags":["scraping","audio","pixabay","data-validation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}