{"record":{"id":"3cf125e7932163df","repo":"langgenius/dify","slug":"unsupported-audio-type-3cf125","errorCode":"unsupported_audio_type","errorMessage":"Audio type not allowed.","messagePattern":"Audio type not allowed\\.","errorType":"error_code","errorClass":"UnsupportedAudioTypeError","httpStatus":415,"severity":"warning","filePath":"api/controllers/console/explore/audio.py","lineNumber":77,"sourceCode":"\n        try:\n            response = AudioService.transcript_asr(\n                app_model=app_model,\n                file=file,\n                session=db.session(),\n                end_user=None,\n            )\n\n            return response\n        except services.errors.app_model_config.AppModelConfigBrokenError:\n            logger.exception(\"App model config broken.\")\n            raise AppUnavailableError()\n        except NoAudioUploadedServiceError:\n            raise NoAudioUploadedError()\n        except AudioTooLargeServiceError as e:\n            raise AudioTooLargeError(str(e))\n        except UnsupportedAudioTypeServiceError:\n            raise UnsupportedAudioTypeError()\n        except ProviderNotSupportSpeechToTextServiceError:\n            raise ProviderNotSupportSpeechToTextError()\n        except SpeechToTextDisabledServiceError:\n            raise SpeechToTextDisabledError()\n        except ProviderTokenNotInitError as ex:\n            raise ProviderNotInitializeError(ex.description)\n        except QuotaExceededError:\n            raise ProviderQuotaExceededError()\n        except ModelCurrentlyNotSupportError:\n            raise ProviderModelCurrentlyNotSupportError()\n        except InvokeError as e:\n            raise CompletionRequestError(e.description)\n        except ValueError as e:\n            raise e\n        except Exception as e:\n            logger.exception(\"internal server error.\")\n            raise InternalServerError()\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/explore/audio.py#L59-L95","documentation":"HTTP 415 UnsupportedAudioTypeError, raised by the STT endpoint POST /installed-apps/{id}/audio-to-text. The uploaded file's MIME type is not in the allowed audio set. The service (_invoke_speech_to_text in services/audio_service.py:133-135) compares file.mimetype against audio/{ext} for ext in AUDIO_EXTENSIONS (mp3, m4a, wav, amr, mpga, case-insensitive). If the Content-Type does not match one of those, the controller re-raises the service error as this HTTP error.","triggerScenarios":"POST /console/explore/installed-apps/{installed_app_id}/audio-to-text with a multipart 'file' whose Content-Type is e.g. audio/ogg, audio/aac, video/mp4, application/octet-stream, or any value outside audio/mp3|m4a|wav|amr|mpga. Also fires if the client omits a Content-Type and Werkzeug infersences a non-whitelisted type.","commonSituations":"Client records audio in a browser format (audio/webm, audio/ogg) not in the allowlist; mobile SDK ships .aac/.opus; file renamed to .mp3 but actual Content-Type header is generic; proxy/CDN rewrites Content-Type to application/octet-stream.","solutions":["Transcode/re-encode the upload to mp3, m4a, wav, amr, or mpga before sending.","Set the multipart Content-Type header explicitly to one of the allowed audio/* MIME values matching the real bytes.","If you control the client SDK, restrict the recorder/encoder output to mp3 or wav.","If a new format is genuinely required, extend AUDIO_EXTENSIONS in api/constants/__init__.py and confirm the speech2text provider model accepts it."],"exampleFix":"// before: recorder produces audio/webm\nform.append('file', blob); // Content-Type: audio/webm -> 415\n// after: transcode to mp3 first\nconst mp3Blob = await transcodeToMp3(blob);\nform.append('file', mp3Blob, 'audio.mp3'); // Content-Type: audio/mp3 -> ok","handlingStrategy":"validation","validationCode":"ALLOWED = {\"mp3\", \"m4a\", \"wav\", \"amr\", \"mpga\"}\nfunction allowedAudio(file: File): boolean {\n  const ext = (file.name.split(\".\").pop() || \"\").toLowerCase()\n  return ALLOWED.has(ext)\n}\n// before upload:\nif (!allowedAudio(file)) throw new Error(\"Convert to mp3/m4a/wav/amr/mpga first\")","typeGuard":"function isAllowedAudioMime(mime: string): boolean {\n  return [\"audio/mp3\",\"audio/m4a\",\"audio/wav\",\"audio/amr\",\"audio/mpga\"].includes(mime.toLowerCase())\n}","tryCatchPattern":"// Fetch is the 415 body and surface 'unsupported_audio_type' to the user with a re-encode prompt.\ntry { await postAudio(file) }\ncatch (e) { if (e.code === 415 && e.error_code === 'unsupported_audio_type') promptReencode() else throw e }","preventionTips":["Restrict the recorder/encoder to mp3 or wav output on the client.","Set the multipart Content-Type explicitly to match the real bytes.","Validate the file extension against the allowlist before opening the upload dialog."],"tags":["audio","stt","validation","mime-type","http-415"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}