calesthio/OpenMontage · error · RuntimeError

Doubao submit succeeded but did not return data.task_id

Error message

Doubao submit succeeded but did not return data.task_id

What it means

Raised after a successful HTTP POST to the Volcengine Doubao TTS submit endpoint when the parsed JSON body lacks data.task_id. The wrapper treats a submit response without a task id as unusable because every later poll of QUERY_URL keys off task_id. Note the message text is a plain string, not an f-string, so the literal '{query_data...}' braces never interpolate the response body.

Source

Thrown at tools/audio/doubao_tts.py:242

        output_path.parent.mkdir(parents=True, exist_ok=True)
        metadata_path.parent.mkdir(parents=True, exist_ok=True)

        req_id = str(uuid.uuid4())
        headers = self._headers(
            api_key=api_key,
            resource_id=resource_id,
            request_id=req_id,
            return_usage=bool(inputs.get("return_usage", True)),
        )
        body = self._submit_body(inputs, voice_id=voice_id, request_id=req_id)

        submit_response = requests.post(self.SUBMIT_URL, headers=headers, json=body, timeout=(10, 60))
        submit_data = self._json_or_raise(submit_response)
        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)

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Log the full submit_data payload when task_id is absent to see the real envelope returned
  2. Verify resource_id matches the current console's speech endpoint and that the X-Api-Key header flow is used
  3. Retry once — transient soft failures occasionally return an empty data object
  4. If the envelope changed upstream, update the key extraction in doubao_tts.py to the new path

Example fix

// before
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")

// after
task_id = (submit_data.get("data") or {}).get("task_id")
if not task_id:
    raise RuntimeError(
        f"Doubao submit succeeded but did not return data.task_id: {submit_data}"
    )
Defensive patterns

Strategy: try-catch

Try / catch

try:
    result = doubao_tool.execute(inputs)
except RuntimeError as e:
    if "data.task_id" in str(e):
        logger.error("doubao submit envelope missing task_id; dumping last response")
        raise
    raise

Prevention

When it happens

Trigger: POST to SUBMIT_URL returns HTTP 200 with code 20000000 but data is missing or has no task_id key (e.g. data: null, data: {}), or the endpoint shape changed / was routed to a different API that returns a different envelope.

Common situations: Volcendpoint/console migration changed the response envelope; the resource_id points at a legacy endpoint; a proxy or gateway stripped fields; the submit actually failed softly but with code 20000000 so _raise_for_doubao_error passed.

Related errors


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/bc897abb9ea24505. Report an issue: GitHub.