calesthio/OpenMontage · error · RuntimeError
No preview URL available for sound {sound.get('id')} ({sound
Error message
No preview URL available for sound {sound.get('id')} ({sound.get('name')}) What it means
Raised by freesound_music._download when a search result's previews object contains neither preview-hq-mp3 nor preview-lq-mp3. Freesound download URLs only exist for sounds whose license/premium state permits previews; the tool downloads the HQ MP3 preview rather than the original file, so a result without preview URLs is undownloadable.
Source
Thrown at tools/audio/freesound_music.py:210
request = urllib.request.Request(
url,
headers={"User-Agent": "OpenMontage/0.1 (music acquisition tool)"},
)
with urllib.request.urlopen(request, timeout=30) as response:
data = json.loads(response.read().decode("utf-8"))
results = data.get("results", [])
return results
def _download(self, sound: dict, inputs: dict[str, Any], api_key: str) -> Path:
"""Download the HQ MP3 preview of a Freesound sound."""
previews = sound.get("previews", {})
# Prefer the HQ MP3 preview; fall back to LQ MP3
audio_url = previews.get("preview-hq-mp3") or previews.get("preview-lq-mp3")
if not audio_url:
raise RuntimeError(
f"No preview URL available for sound {sound.get('id')} ({sound.get('name')})"
)
# Build output path
sound_name = sound.get("name", f"freesound_{sound.get('id', 'unknown')}")
safe_name = "".join(c if c.isalnum() or c in "._- " else "_" for c in sound_name)
default_filename = f"freesound_{sound.get('id')}_{safe_name}.mp3"
output_path = Path(inputs.get("output_path", default_filename))
output_path.parent.mkdir(parents=True, exist_ok=True)
request = urllib.request.Request(
audio_url,
headers={"User-Agent": "OpenMontage/0.1 (music acquisition tool)"},
)
with urllib.request.urlopen(request, timeout=60) as response:
output_path.write_bytes(response.read())
View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Filter search results client-side: prefer items where result['previews'].get('preview-hq-mp3') is truthy
- Fall back to the next search result instead of failing the whole job
- Request additional fields in the search query so previews are populated
Example fix
// before
sound = results[0] # may lack previews
// after
sound = next(r for r in results if r.get("previews", {}).get("preview-hq-mp3") or r.get("previews", {}).get("preview-lq-mp3")) Defensive patterns
Strategy: validation
Validate before calling
def downloadable(sound: dict) -> bool:
p = sound.get("previews") or {}
return bool(p.get("preview-hq-mp3") or p.get("preview-lq-mp3"))
results = [r for r in results if downloadable(r)] Type guard
def has_preview(sound: dict) -> bool:
previews = sound.get("previews")
return isinstance(previews, dict) and bool(
previews.get("preview-hq-mp3") or previews.get("preview-lq-mp3")
) Prevention
- Filter search results on preview presence before selection
- Iterate candidates with fallback rather than taking results[0]
- Request the previews field explicitly in search queries
When it happens
Trigger: Search returns a premium-only or delisted sound whose previews dict is empty; result objects from a stale/paginated search response missing the previews field.
Common situations: Picking the first search hit without checking its previews; sounds uploaded with original-only licensing; API response shape differences between search endpoints.
Related errors
- Kling TTS response item contained no downloadable URL: {item
- No prompt_id in response: {data}
- Kling Classic create response missing data.task_id: {data}
- Atlas Cloud returned an unexpected payload: {str(body)[:500]
- Atlas Cloud returned an unexpected 'data' field: {str(data)[
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/cb8691b4b2feda03.
Report an issue: GitHub.