iflytek/astron-agent · error · ServiceException
CodeEnums.ServiceResponseError
CodeEnums.ServiceResponseError
Error message
<dynamic message from TTS response header>
What it means
During streaming TTS synthesis, each WebSocket message from the iFlytek TTS endpoint carries a header with a return `code`. A non-zero code means the TTS backend rejected or failed the synthesis request; the service re-raises it as a ServiceResponseError with the backend's own `message` from the response header. This is an upstream API error surfaced verbatim to the caller.
Solutions
- Read the dynamic `message` in the error — it names the exact iFlytek error; fix the indicated parameter (usually auth, quota, or vcn).
- Verify TTS_URL_KEY env var points to the correct iFlytek TTS websocket gateway for your API version.
- Check the credentials returned by get_iflytek_open_platform_credentials (app_id, API key, API secret) are valid and not expired.
- Retry after backoff if the message indicates quota/concurrency limits; otherwise correct the request parameters (vcn, speed, text length).
Example fix
// before
const vcn = userSelectedVoice; // may be 'unknown_voice'
await smartTts({ text, vcn });
// after
const ALLOWED_VCNS = ['xiaoyan', 'aisjiuxu', 'xiaoqi'];
if (!ALLOWED_VCNS.includes(userSelectedVoice)) userSelectedVoice = 'xiaoyan';
await smartTts({ text, vcn: userSelectedVoice }); Defensive patterns
Strategy: retry
Validate before calling
def tts_request_is_sane(body, creds) -> bool:
return bool(body.text) and len(body.text) < 8000 and bool(creds.app_id) and body.vcn in KNOWN_VCNS Try / catch
try:
resp = await smart_tts_service(body, request)
except ServiceException as e:
logger.error('TTS upstream error: %s', e.message)
if 'quota' in e.message or 'concurrent' in e.message:
await asyncio.sleep(retry_after)
resp = await smart_tts_service(body, request)
else:
raise Prevention
- Monitor iFlytek quota and concurrency usage; alert before exhaustion.
- Validate vcn and speed against known-good values before calling.
- Keep TTS_URL_KEY and credentials in checked configuration with startup validation.
- Surface the upstream header message to logs on every failure for fast diagnosis.
When it happens
Trigger: The async loop `async for msg in client.recv()` receives a frame whose header code != 0 — e.g. invalid/expired iFlytek Open Platform credentials (app_id/API key), quota or concurrency limits exhausted, invalid voice name (vcn) or audio parameters, or malformed text causing backend rejection.
Common situations: TTS_URL_KEY points to a wrong or stale gateway URL; credentials configured via get_iflytek_open_platform_credentials are wrong, rotated, or expired; free-tier daily quota or concurrent-connection limit exceeded; unsupported vcn value passed in the request.
Related errors
- RESPONSE_FAILED
- SPEAKER_TRAIN_FAILED
- convertTextErrorCodeToResponseEnum(listener.getErrorCode())
- Invalid host URL or authentication parameters
- RESPONSE_FAILED
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/4fd4271be1eb1d58.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/aitools/service/smart_tts/smart_tts_service.py:116
audio_data = bytearray()
async with WebSocketClient(
url=url,
span=span,
auth="ASE",
app_id=credentials.app_id,
api_key=credentials.api_key,
api_secret=credentials.api_secret,
).start() as client:
await client.send(json.dumps(data))
async for msg in client.recv():
message_dict = json.loads(msg)
code = message_dict.get("header", {}).get("code", 0)
message = message_dict.get("header", {}).get("message", "")
if code != 0:
raise ServiceException.from_error_code(
CodeEnums.ServiceResponseError, extra_message=message
)
if "payload" in message_dict:
audio = base64.b64decode(message_dict["payload"]["audio"]["audio"])
status = message_dict["payload"]["audio"]["status"]
if status == 2:
break
audio_data.extend(audio)
if not audio_data:
raise ServiceException.from_error_code(
CodeEnums.ServiceResponseError, extra_message="音频数据为空"
)
voice_url = await upload_file(str(uuid.uuid4()) + ".MP3", audio_data, span)View on GitHub (pinned to 5e758547a8)