BerriAI/litellm · error · Exception
dynamic_api_key needs to be a string. dynamic_api_key={dynam
Error message
dynamic_api_key needs to be a string. dynamic_api_key={dynamic_api_key} What it means
dynamic_api_key string check on the OpenAI-compatible-endpoint path: after resolving a known endpoint (perplexity/deepinfra/wandb/meta/...), the dynamic_api_key resolved from arguments or env is not a string.
Source
Thrown at litellm/litellm_core_utils/get_llm_provider_logic.py:356
custom_llm_provider = "hyperbolic"
dynamic_api_key = get_secret_str("HYPERBOLIC_API_KEY")
elif endpoint == "https://ai-gateway.vercel.sh/v1":
custom_llm_provider = "vercel_ai_gateway"
dynamic_api_key = get_secret_str("VERCEL_AI_GATEWAY_API_KEY")
elif endpoint == "https://api.inference.wandb.ai/v1":
custom_llm_provider = "wandb"
dynamic_api_key = get_secret_str("WANDB_API_KEY")
elif endpoint == "https://pinstripes.io/v1":
custom_llm_provider = "pinstripes"
dynamic_api_key = get_secret_str("PINSTRIPES_API_KEY")
elif endpoint == "https://api.meta.ai/v1":
custom_llm_provider = "meta"
dynamic_api_key = get_secret_str("META_API_KEY")
if api_base is not None and not isinstance(api_base, str):
raise Exception(f"api base needs to be a string. api_base={api_base}")
if dynamic_api_key is not None and not isinstance(dynamic_api_key, str):
raise Exception(f"dynamic_api_key needs to be a string. dynamic_api_key={dynamic_api_key}")
return model, custom_llm_provider, dynamic_api_key, api_base
# check if model in known model provider list -> for huggingface models, raise exception as they don't have a fixed provider (can be togetherai, anyscale, baseten, runpod, et.)
## openai - chatcompletion + text completion
if (
model in litellm.open_ai_chat_completion_models
or "ft:gpt-3.5-turbo" in model
or "ft:gpt-4" in model # catches ft:gpt-4-0613, ft:gpt-4o
or model in litellm.openai_image_generation_models
or model.startswith("gpt-image")
or model in litellm.openai_video_generation_models
):
custom_llm_provider = "openai"
elif model in litellm.open_ai_text_completion_models:
custom_llm_provider = "text-completion-openai"
## anthropic
elif model in litellm.anthropic_models:
if litellm.AnthropicTextConfig._is_anthropic_text_model(model):View on GitHub (pinned to 6c2dcb801b)
Solutions
- Ensure the api_key argument is the string value of the credential.
- Decode bytes keys: api_key.decode() where applicable.
- Unwrap SecretStr via get_secret_value().
Example fix
# before litellm.completion(model='openai/...', api_base='https://api.deepinfra.com/v1/openai', api_key=b'sk-...') # after litellm.completion(model='openai/...', api_base='https://api.deepinfra.com/v1/openai', api_key='sk-...')
Defensive patterns
Strategy: validation
Validate before calling
def resolved_key_is_str(key) -> bool:
return key is None or isinstance(key, str) Prevention
- Normalize secrets to str at ingestion from secret managers.
- Prefer env-var string resolution over injecting objects.
- Add a preflight check over call kwargs: all values str or None.
When it happens
Trigger: Provider endpoint matched but a non-string api_key object was supplied, or a get_secret_str-style lookup returned a non-string object injected by custom secret tooling.
Common situations: Secret managers returning objects/bytes, Pydantic SecretStr, or config loading code that stores credentials as dicts.
Related errors
- dynamic_api_key needs to be a string. Got type={type(dynamic
- An error occurred: {str(e)}, banned_keywords_list={banned_ke
- Invalid mode: {custom_auth_settings['mode']}
- Filtering by 'provider' is not supported when using managed
- Filtering by 'target_model_names' is not supported when usin
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/2fd924630369fb96.
Report an issue: GitHub.