microsoft/semantic-kernel · error · ServiceInvalidRequestError
Audio content uri must be a string to a local file.
Error message
Audio content uri must be a string to a local file.
What it means
Raised by OpenAIAudioToTextBase.get_text_contents — a ServiceInvalidRequestError (not ServiceInitializationError). The OpenAI audio transcription API uploads a local file, so audio_content.uri must be a plain Python str pointing to a file on disk. If uri is any other type (pathlib.Path, HttpUrl, bytes, None, or a pydantic Url object), this check fails. This is a runtime error during transcription, not during service construction.
Source
Thrown at python/semantic_kernel/connectors/ai/open_ai/services/open_ai_audio_to_text_base.py:46
async def get_text_contents(
self,
audio_content: AudioContent,
settings: PromptExecutionSettings | None = None,
**kwargs: Any,
) -> list[TextContent]:
if not settings:
settings = OpenAIAudioToTextExecutionSettings(ai_model_id=self.ai_model_id)
else:
if not isinstance(settings, OpenAIAudioToTextExecutionSettings):
settings = self.get_prompt_execution_settings_from_settings(settings)
assert isinstance(settings, OpenAIAudioToTextExecutionSettings) # nosec
if settings.ai_model_id is None:
settings.ai_model_id = self.ai_model_id
if not isinstance(audio_content.uri, str):
raise ServiceInvalidRequestError("Audio content uri must be a string to a local file.")
settings.filename = audio_content.uri
response = await self._send_request(settings)
assert isinstance(response, Transcription) # nosec
return [
TextContent(
ai_model_id=settings.ai_model_id,
text=response.text,
inner_content=response,
)
]
def get_prompt_execution_settings_class(self) -> type[PromptExecutionSettings]:
"""Get the request settings class."""
return OpenAIAudioToTextExecutionSettings
View on GitHub (pinned to c028a0c7dc)
Solutions
- Ensure audio_content.uri is a str: convert pathlib.Path with str(path) before creating AudioContent.
- If the audio is remote, download it to a local temp file first, then create AudioContent with the local path.
- Check isinstance(audio_content.uri, str) before calling get_text_contents.
- Use AudioContent.from_file(path) or set uri=str(local_path) explicitly.
Example fix
# before (pathlib.Path object as uri)
from pathlib import Path
from semantic_kernel.contents import AudioContent
audio = AudioContent(uri=Path('/data/audio.mp3'))
result = await service.get_text_contents(audio)
# after (convert to str)
audio = AudioContent(uri=str(Path('/data/audio.mp3')))
result = await service.get_text_contents(audio) Defensive patterns
Strategy: type-guard
Validate before calling
from pathlib import Path
from semantic_kernel.contents import AudioContent
def create_audio_content_for_transcription(file_path: str | Path) -> AudioContent:
"""Ensure uri is a str for the OpenAI audio transcription endpoint."""
if isinstance(file_path, Path):
file_path = str(file_path)
if not isinstance(file_path, str):
raise TypeError(f'Audio file path must be str or Path, got {type(file_path).__name__}')
return AudioContent(uri=file_path) Type guard
from semantic_kernel.contents import AudioContent
def is_valid_audio_content_for_transcription(audio_content: AudioContent) -> bool:
"""The OpenAI audio transcription API requires a local file path (str) as uri."""
return isinstance(audio_content.uri, str) Try / catch
from semantic_kernel.exceptions.service_exceptions import ServiceInvalidRequestError
try:
result = await service.get_text_contents(audio_content)
except ServiceInvalidRequestError as e:
if 'uri must be a string' in str(e):
# Convert the uri to str and retry, or download remote audio to a local file
if hasattr(audio_content.uri, '__fspath__'): # pathlib.Path
audio_content.uri = str(audio_content.uri)
result = await service.get_text_contents(audio_content)
else:
raise TypeError('Download remote audio to a local file first') from e
raise Prevention
- Always convert pathlib.Path to str before creating AudioContent: AudioContent(uri=str(path)).
- For remote audio, download to a local temp file before transcription — the OpenAI API requires a file upload.
- Add a type check isinstance(audio_content.uri, str) before calling get_text_contents.
- Never pass an HttpUrl or data URI object as audio_content.uri.
When it happens
Trigger: Calling service.get_text_contents(audio_content) where audio_content.uri is not a str — e.g. a pathlib.Path object, a pydantic HttpsUrl/Url instance, a remote HTTPS URL object, or None. The OpenAI Whisper API requires a local file path to open and upload via multipart form data.
Common situations: Creating AudioContent from a pathlib.Path without converting to str; passing an AudioContent whose data was loaded from a remote URL (uri is an HttpUrl object); using AudioContent.from_bytes() where uri is not set or is a data URI; forgetting that the OpenAI audio endpoint requires a local file, not a URL.
Related errors
- The input audio content is not readable.
- The audio transcription format '{responseFormat}' is not sup
- Failed to create OpenAI settings.
- The OpenAI audio to text model ID is required.
- The settings must be an OpenAIChatPromptExecutionSettings.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/131f0d3cb4ea6723.
Report an issue: GitHub.