calesthio/OpenMontage · error · RuntimeError
Doubao task completed but did not return data.audio_url
Error message
Doubao task completed but did not return data.audio_url
What it means
Raised when the Doubao async TTS polling loop reports task_status == 2 (success) but the returned data object contains no audio_url. The wrapper refuses to continue because the next step downloads the audio from that URL. The literal-brace message never interpolates, so the actual payload is invisible unless you instrument it.
Source
Thrown at tools/audio/doubao_tts.py:256
self._raise_for_doubao_error(submit_response.status_code, submit_data)
task_id = submit_data.get("data", {}).get("task_id")
if not task_id:
raise RuntimeError("Doubao submit succeeded but did not return data.task_id")
query_data = self._poll_query(
requests_module=requests,
api_key=api_key,
resource_id=resource_id,
task_id=task_id,
return_usage=bool(inputs.get("return_usage", True)),
poll_interval=float(inputs.get("poll_interval_seconds", 2.0)),
timeout_seconds=int(inputs.get("timeout_seconds", 300)),
)
data = query_data.get("data", {})
audio_url = data.get("audio_url")
if not audio_url:
raise RuntimeError("Doubao task completed but did not return data.audio_url")
audio_response = requests.get(audio_url, timeout=(10, 120))
audio_response.raise_for_status()
output_path.write_bytes(audio_response.content)
metadata_path.write_text(json.dumps(query_data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
audio_duration = self._audio_duration(output_path)
usage = data.get("usage")
cost = self._cost_from_usage(usage) or self.estimate_cost(inputs)
return ToolResult(
success=True,
data={
"provider": self.provider,
"model": resource_id,
"resource_id": resource_id,
"voice_id": voice_id,
"format": fmt,View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Persist query_data to a debug log and inspect which keys data actually carries (sometimes the URL moved to data.audio.url or similar)
- Retry the whole submit — a fresh task usually produces a fresh audio_url
- Shorten the gap between completion and download by lowering poll_interval_seconds
- Confirm the resource_id/endpoint pairing matches the current Volcengine console
Defensive patterns
Strategy: retry
Try / catch
for attempt in range(2):
try:
result = doubao_tool.execute(inputs)
break
except RuntimeError as e:
if "audio_url" in str(e) and attempt == 0:
continue # re-submit: completed task lost its artifact
raise Prevention
- Keep poll_interval_seconds small so download happens soon after completion
- Persist metadata_path output so any successful query payload is auditable
- Treat missing-audio_url-on-success as retryable, not as a config bug
When it happens
Trigger: QUERY_URL returns status 2 with data.audio_url missing/null/empty — expired or purged audio, partial server-side success, or an envelope change in the query response.
Common situations: Long polls where the audio expired between completion and query; region/console migration altering the response schema; account state (quota exhausted mid-task) producing a 'succeeded' status with no artifact.
Related errors
- Doubao submit succeeded but did not return data.task_id
- Doubao task failed: {query_data.get('message', 'unknown erro
- Prediction {prediction_id} reported '{last_status}' but retu
- Kling TTS create response missing data.task_id: {data}
- Kling TTS result path data.task_result.audios is not a list
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/75f1674af9ae8d68.
Report an issue: GitHub.