{"record":{"id":"80673dc5334ab56f","repo":"langgenius/dify","slug":"no-audio-uploaded-80673d","errorCode":"no_audio_uploaded","errorMessage":"Please upload your audio.","messagePattern":"Please upload your audio\\.","errorType":"error_code","errorClass":"NoAudioUploadedError","httpStatus":400,"severity":"error","filePath":"api/controllers/console/explore/trial.py","lineNumber":684,"sourceCode":"\n        try:\n            # Get IDs before they might be detached from session\n            app_id = app_model.id\n            user_id = current_user.id\n\n            response = AudioService.transcript_asr(\n                app_model=app_model,\n                file=file,\n                session=db.session(),\n                end_user=None,\n            )\n            RecommendedAppService.add_trial_app_record(app_id, user_id, session=db.session())\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","sourceCodeStart":666,"sourceCodeEnd":702,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/explore/trial.py#L666-L702","documentation":"HTTP 400 with error_code `no_audio_uploaded`, raised by NoAudioUploadedError when AudioService.transcript_asr raises NoAudioUploadedServiceError. The multipart request did not include an audio file under the expected field. The controller reads `request.files.get(\"file\")` and the service validates it; absence yields this error before any provider call.","triggerScenarios":"POST TrialChatAudioApi with a request body that omits the 'file' part, sends it under a different field name, or sends an empty/multipart boundary that Flask did not parse as an upload.","commonSituations":"Frontend sent JSON instead of multipart/form-data; the file input field name is not exactly 'file'; the browser dropped the attachment on a slow connection; curl invocation forgot -F file=@...","solutions":["Send the audio as multipart/form-data with the field name 'file': `curl -F file=@audio.mp3 <url>`.","On the frontend, confirm the FormData appends under key 'file' and the request Content-Type is multipart (let the browser set the boundary).","Validate the file is non-empty before submitting."],"exampleFix":"// before - sent as JSON\nfetch(url, { method: 'POST', body: JSON.stringify({}) })\n\n// after - multipart with field 'file'\nconst fd = new FormData()\nfd.append('file', audioBlob, 'audio.webm')\nfetch(url, { method: 'POST', body: fd })","handlingStrategy":"validation","validationCode":"if (!(file instanceof Blob && file.size > 0)) {\n  throw new Error('attach a non-empty audio file')\n}\nconst fd = new FormData()\nfd.append('file', file, file.name || 'audio.webm')","typeGuard":"function isValidAudioUpload(file: unknown): file is Blob {\n  return file instanceof Blob && file.size > 0\n}","tryCatchPattern":"try {\n  const r = await fetch(audioUrl, { method: 'POST', body: fd })\n  if (r.status === 400) {\n    const body = await r.json()\n    if (body.code === 'no_audio_uploaded') promptReattachFile()\n  }\n} catch (e) { reportToUser(e) }","preventionTips":["Always POST audio as multipart/form-data with field name 'file'.","Do not set Content-Type manually for FormData; let the browser set the boundary.","Disable the submit button until a non-empty file is attached."],"tags":["dify","trial-api","console","explore","audio","upload","multipart","http-400","validation"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}