{"record":{"id":"131f0d3cb4ea6723","repo":"microsoft/semantic-kernel","slug":"audio-content-uri-must-be-a-string-to-a-local-file","errorCode":null,"errorMessage":"Audio content uri must be a string to a local file.","messagePattern":"Audio content uri must be a string to a local file\\.","errorType":"exception","errorClass":"ServiceInvalidRequestError","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/ai/open_ai/services/open_ai_audio_to_text_base.py","lineNumber":46,"sourceCode":"    async def get_text_contents(\n        self,\n        audio_content: AudioContent,\n        settings: PromptExecutionSettings | None = None,\n        **kwargs: Any,\n    ) -> list[TextContent]:\n        if not settings:\n            settings = OpenAIAudioToTextExecutionSettings(ai_model_id=self.ai_model_id)\n        else:\n            if not isinstance(settings, OpenAIAudioToTextExecutionSettings):\n                settings = self.get_prompt_execution_settings_from_settings(settings)\n\n        assert isinstance(settings, OpenAIAudioToTextExecutionSettings)  # nosec\n\n        if settings.ai_model_id is None:\n            settings.ai_model_id = self.ai_model_id\n\n        if not isinstance(audio_content.uri, str):\n            raise ServiceInvalidRequestError(\"Audio content uri must be a string to a local file.\")\n\n        settings.filename = audio_content.uri\n\n        response = await self._send_request(settings)\n        assert isinstance(response, Transcription)  # nosec\n\n        return [\n            TextContent(\n                ai_model_id=settings.ai_model_id,\n                text=response.text,\n                inner_content=response,\n            )\n        ]\n\n    def get_prompt_execution_settings_class(self) -> type[PromptExecutionSettings]:\n        \"\"\"Get the request settings class.\"\"\"\n        return OpenAIAudioToTextExecutionSettings\n","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/ai/open_ai/services/open_ai_audio_to_text_base.py#L28-L64","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (pathlib.Path object as uri)\nfrom pathlib import Path\nfrom semantic_kernel.contents import AudioContent\n\naudio = AudioContent(uri=Path('/data/audio.mp3'))\nresult = await service.get_text_contents(audio)\n\n# after (convert to str)\naudio = AudioContent(uri=str(Path('/data/audio.mp3')))\nresult = await service.get_text_contents(audio)","handlingStrategy":"type-guard","validationCode":"from pathlib import Path\nfrom semantic_kernel.contents import AudioContent\n\ndef create_audio_content_for_transcription(file_path: str | Path) -> AudioContent:\n    \"\"\"Ensure uri is a str for the OpenAI audio transcription endpoint.\"\"\"\n    if isinstance(file_path, Path):\n        file_path = str(file_path)\n    if not isinstance(file_path, str):\n        raise TypeError(f'Audio file path must be str or Path, got {type(file_path).__name__}')\n    return AudioContent(uri=file_path)","typeGuard":"from semantic_kernel.contents import AudioContent\n\ndef is_valid_audio_content_for_transcription(audio_content: AudioContent) -> bool:\n    \"\"\"The OpenAI audio transcription API requires a local file path (str) as uri.\"\"\"\n    return isinstance(audio_content.uri, str)","tryCatchPattern":"from semantic_kernel.exceptions.service_exceptions import ServiceInvalidRequestError\n\ntry:\n    result = await service.get_text_contents(audio_content)\nexcept ServiceInvalidRequestError as e:\n    if 'uri must be a string' in str(e):\n        # Convert the uri to str and retry, or download remote audio to a local file\n        if hasattr(audio_content.uri, '__fspath__'):  # pathlib.Path\n            audio_content.uri = str(audio_content.uri)\n            result = await service.get_text_contents(audio_content)\n        else:\n            raise TypeError('Download remote audio to a local file first') from e\n    raise","preventionTips":["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."],"tags":["openai","audio-to-text","type-validation","local-file","runtime"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}