BerriAI/litellm · error · ValueError
prompt_characters must be provided for tts calls. prompt_cha
Error message
prompt_characters must be provided for tts calls. prompt_characters={prompt_characters}, model={model}, custom_llm_provider={custom_llm_provider}, call_type={call_type} What it means
For text-to-speech calls priced per character (e.g. OpenAI TTS models in LiteLLM's cost map), the calculator needs the input length. If call_type is 'speech'/'aspeech', the model's cost metric resolves to 'cost_per_character', and prompt_characters is None, it raises ValueError instead of guessing a cost.
Source
Thrown at litellm/cost_calculator.py:495
"""
if model_with_provider in model_cost_ref: # Option 2. use model with provider, model = "openai/gpt-4"
model = model_with_provider
elif model in model_cost_ref: # Option 1. use model passed, model="gpt-4"
model = model
elif (
model_without_prefix in model_cost_ref
): # Option 3. if user passed model="bedrock/anthropic.claude-3", use model="anthropic.claude-3"
model = model_without_prefix
# see this https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models
if call_type == "speech" or call_type == "aspeech":
speech_model_info = litellm.get_model_info(model=model_without_prefix, custom_llm_provider=custom_llm_provider)
cost_metric: Final = select_cost_metric_for_model(speech_model_info)
prompt_cost: float = 0.0
completion_cost: float = 0.0
if cost_metric == "cost_per_character":
if prompt_characters is None:
raise ValueError(
f"prompt_characters must be provided for tts calls. prompt_characters={prompt_characters}, model={model}, custom_llm_provider={custom_llm_provider}, call_type={call_type}"
)
_prompt_cost, _completion_cost = _generic_cost_per_character(
model=model_without_prefix,
custom_llm_provider=custom_llm_provider,
prompt_characters=prompt_characters,
completion_characters=0,
custom_prompt_cost=None,
custom_completion_cost=0,
)
if _prompt_cost is None or _completion_cost is None:
raise ValueError(
f"cost for tts call is None. prompt_cost={_prompt_cost}, completion_cost={_completion_cost}, model={model_without_prefix}, custom_llm_provider={custom_llm_provider}, prompt_characters={prompt_characters}, completion_characters={completion_characters}"
)
prompt_cost = _prompt_cost
completion_cost = _completion_cost
elif cost_metric == "cost_per_token":
prompt_cost, completion_cost = generic_cost_per_token(View on GitHub (pinned to 6c2dcb801b)
Solutions
- Pass prompt_characters=len(input_text) to completion_cost for speech calls.
- Let LiteLLM's own logging path compute it — call the speech API through the standard litellm.speech(...) wrapper rather than computing cost manually.
- Update LiteLLM if an older version failed to thread prompt_characters through its logging object.
- For per-token-priced TTS models no characters are needed; confirm which metric applies via litellm.get_model_info(model)['cost_metric'] or the model's pricing keys.
Example fix
# before
cost = litellm.completion_cost(
model="tts-1", call_type="speech", prompt="hello world",
)
# after
cost = litellm.completion_cost(
model="tts-1", call_type="speech", prompt="hello world",
prompt_characters=len("hello world"),
) Defensive patterns
Strategy: validation
Validate before calling
if call_type in ("speech", "aspeech"):
info = litellm.get_model_info(model=model_without_prefix, custom_llm_provider=custom_llm_provider)
if "input_cost_per_character" in (info or {}):
assert prompt_characters is not None, "pass prompt_characters=len(text) for per-character TTS pricing"
prompt_characters = prompt_characters if prompt_characters is not None else len(input_text) Type guard
def tts_cost_ready(model: str, text: str, prompt_characters: int | None) -> bool:
if prompt_characters is not None:
return True
try:
info = litellm.get_model_info(model=model) or {}
return "input_cost_per_character" not in info
except Exception:
return False Try / catch
try:
cost = litellm.completion_cost(model=model, call_type="speech", prompt=text, prompt_characters=len(text))
except ValueError as e:
if "prompt_characters must be provided" in str(e):
cost = litellm.completion_cost(model=model, call_type="speech", prompt=text, prompt_characters=len(text))
else:
raise Prevention
- For any TTS cost call, always pass prompt_characters=len(input_string).
- Prefer litellm's built-in logging for speech calls instead of manual cost computation.
- Write a helper that computes TTS cost so the character count is never forgotten.
When it happens
Trigger: Invoking litellm.speech()/aspeech and then completion_cost (usually via logging) without prompt_characters; calling completion_cost(call_type='speech') on a model whose model_info uses cost_per_character while omitting the character count.
Common situations: Custom wrappers that compute TTS costs from a response object only; models newly switched to per-character pricing in a LiteLLM upgrade; forgetting that TTS responses carry audio, not token usage.
Related errors
- Invalid arg. Model cannot be none.
- cost for tts call is None. prompt_cost={_prompt_cost}, compl
- model is required
- input is required
- soft_budget cannot be negative. Received: {data.soft_budget}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/49f507c9404e11ea.
Report an issue: GitHub.