Documentation
Error Handling Learn how to handle errors from SM-AI-MODELS APIs.
Error Response Format
All error responses follow this format:
{
"error" : {
"code" : "error_code" ,
"message" : "Human-readable error message"
}
}
HTTP Status Codes
Status Description Action 200Success Process response 400Bad Request Check input parameters 500Server Error Retry or contact support 503Service Unavailable Service is starting up, retry later
Common Errors
TTS Errors
Code Message Cause Solution invalid_requestInput text is required Missing input field Provide the input parameter invalid_voiceUnknown voice Invalid voice name Use: Yara, Nouf, or Yara_en invalid_formatUnsupported format Invalid response_format Use: mp3, wav, opus, or flac invalid_speedSpeed must be between 0.25 and 4.0 Speed out of valid range Use value between 0.25 and 4.0 text_too_longInput exceeds maximum length Text is too long Split text into smaller chunks
Example TTS error response:
{
"error" : {
"code" : "invalid_speed" ,
"message" : "Speed must be between 0.25 and 4.0"
}
}
ASR Errors
Code Message Cause Solution invalid_fileFile is required No file uploaded Provide audio file in request unsupported_formatUnsupported audio format Invalid file type Use: flac, mp3, wav, ogg, or webm file_too_largeFile exceeds maximum size Audio file too large Compress or split audio file corrupt_audioCannot process audio Corrupted audio file Verify file integrity
Example ASR error response:
{
"error" : {
"code" : "unsupported_format" ,
"message" : "Unsupported audio format"
}
}
Retry Strategy
For transient errors (500, 503), implement exponential backoff:
import time
import requests
def request_with_retry (url, data, max_retries = 3 ):
for attempt in range (max_retries):
try :
response = requests.post(url, json = data, timeout = 30 )
if response.status_code == 200 :
return response
if response.status_code in [ 500 , 503 ]:
# Retry with exponential backoff
wait_time = ( 2 ** attempt) + 1
print ( f "Retry { attempt + 1} / { max_retries } in { wait_time } s" )
time.sleep(wait_time)
continue
# Don't retry client errors
response.raise_for_status()
except requests.Timeout:
if attempt < max_retries - 1 :
continue
raise
raise Exception ( "Max retries exceeded" )
Validation
Validate inputs before making requests:
def validate_tts_request (text, voice, format, speed):
errors = []
if not text or not text.strip():
errors.append( "Input text is required" )
if voice not in [ 'Yara' , 'Nouf' , 'Yara_en' ]:
errors.append( f "Invalid voice: { voice } " )
if format not in [ 'mp3' , 'wav' , 'opus' , 'flac' ]:
errors.append( f "Invalid format: {format} " )
if not ( 0.25 <= speed <= 4.0 ):
errors.append( f "Speed must be between 0.25 and 4.0" )
return errors
Logging
Log errors for debugging:
import logging
logging.basicConfig( level = logging. INFO )
logger = logging.getLogger( __name__ )
def generate_speech_with_logging (text, voice = "Yara" ):
try :
response = requests.post(
"http://localhost:9999/v1/audio/speech" ,
json = { "input" : text, "voice" : voice}
)
if response.status_code != 200 :
error = response.json()
logger.error( f "TTS error: { error } " )
return None
logger.info( f "Generated speech for {len (text) } chars" )
return response.content
except Exception as e:
logger.exception( f "TTS request failed: { e } " )
return None
Health Checks
Check service health before making requests:
def ensure_service_healthy (service_url, timeout = 5 ):
try :
response = requests.get(
f " { service_url } /health" ,
timeout = timeout
)
data = response.json()
return data.get( "status" ) == "healthy"
except :
return False
# Usage
if ensure_service_healthy( "http://localhost:9999" ):
audio = generate_speech( "مرحباً" )
else :
print ( "TTS service not available" )
API Limits
For detailed information about API limits and constraints, see the API Limits documentation .
Key Limits
TTS speed range: 0.25 to 4.0
TTS voices: Yara, Nouf, Yara_en
TTS formats: mp3, wav, opus, flac
ASR formats: flac, mp3, wav, ogg, webm
Recommended audio duration: Under 30 seconds for optimal performance
Complete Error Handling Example
import requests
import logging
from time import sleep
logging.basicConfig( level = logging. INFO )
logger = logging.getLogger( __name__ )
class SMAIClient :
def __init__ (self, tts_url = "http://localhost:9999" , asr_url = "http://localhost:8088" ):
self .tts_url = tts_url
self .asr_url = asr_url
def generate_speech (self, text, voice = "Yara" , format = "mp3" , speed = 1.0 , max_retries = 3 ):
"""Generate speech with comprehensive error handling."""
# Validate inputs
if not text or not text.strip():
raise ValueError ( "Input text is required" )
if voice not in [ 'Yara' , 'Nouf' , 'Yara_en' ]:
raise ValueError ( f "Invalid voice: { voice } . Use Yara, Nouf, or Yara_en" )
if format not in [ 'mp3' , 'wav' , 'opus' , 'flac' ]:
raise ValueError ( f "Invalid format: {format} " )
if not ( 0.25 <= speed <= 4.0 ):
raise ValueError ( f "Speed must be between 0.25 and 4.0, got { speed } " )
# Make request with retry
for attempt in range (max_retries):
try :
response = requests.post(
f " {self .tts_url } /v1/audio/speech" ,
json = {
"input" : text,
"voice" : voice,
"response_format" : format ,
"speed" : speed
},
timeout = 30
)
if response.status_code == 200 :
logger.info( f "Speech generated successfully ( {len (text) } chars)" )
return response.content
# Handle server errors with retry
if response.status_code in [ 500 , 503 ]:
wait_time = ( 2 ** attempt) + 1
logger.warning( f "Server error, retrying in { wait_time } s..." )
sleep(wait_time)
continue
# Handle client errors
error_data = response.json()
error_msg = error_data.get( "error" , {}).get( "message" , "Unknown error" )
logger.error( f "TTS error ( { response.status_code } ): { error_msg } " )
raise Exception ( f "TTS failed: { error_msg } " )
except requests.Timeout:
if attempt < max_retries - 1 :
logger.warning( f "Request timeout, retrying..." )
continue
raise Exception ( "Request timed out after retries" )
except requests.ConnectionError:
logger.error( "Cannot connect to TTS service" )
raise Exception ( "TTS service unavailable" )
raise Exception ( "Max retries exceeded" )
def transcribe (self, audio_path, max_retries = 3 ):
"""Transcribe audio with comprehensive error handling."""
import os
# Validate file
if not os.path.exists(audio_path):
raise FileNotFoundError ( f "Audio file not found: { audio_path } " )
file_ext = os.path.splitext(audio_path)[ 1 ].lower()
if file_ext not in [ '.flac' , '.mp3' , '.wav' , '.ogg' , '.webm' ]:
raise ValueError ( f "Unsupported format: { file_ext } " )
# Make request with retry
for attempt in range (max_retries):
try :
with open (audio_path, "rb" ) as f:
response = requests.post(
f " {self .asr_url } /v1/audio/transcriptions" ,
files = { "file" : f},
timeout = 60
)
if response.status_code == 200 :
text = response.json()[ "text" ]
logger.info( f "Transcription successful: {len (text) } chars" )
return text
# Handle server errors with retry
if response.status_code in [ 500 , 503 ]:
wait_time = ( 2 ** attempt) + 1
logger.warning( f "Server error, retrying in { wait_time } s..." )
sleep(wait_time)
continue
# Handle client errors
error_data = response.json()
error_msg = error_data.get( "error" , {}).get( "message" , "Unknown error" )
logger.error( f "ASR error ( { response.status_code } ): { error_msg } " )
raise Exception ( f "Transcription failed: { error_msg } " )
except requests.Timeout:
if attempt < max_retries - 1 :
logger.warning( f "Request timeout, retrying..." )
continue
raise Exception ( "Request timed out after retries" )
except requests.ConnectionError:
logger.error( "Cannot connect to ASR service" )
raise Exception ( "ASR service unavailable" )
raise Exception ( "Max retries exceeded" )
# Usage
client = SMAIClient()
try :
audio = client.generate_speech( "مرحباً بكم" , voice = "Yara" )
with open ( "output.mp3" , "wb" ) as f:
f.write(audio)
print ( "✓ Speech generated" )
except Exception as e:
print ( f "✗ Failed: { e } " )
try :
text = client.transcribe( "recording.wav" )
print ( f "✓ Transcribed: { text } " )
except Exception as e:
print ( f "✗ Failed: { e } " )
Next Steps
Last modified on February 7, 2026