langgenius/dify · error · FileUploadError
FormData is required for audio uploads
Error message
FormData is required for audio uploads
What it means
Thrown by audioToText() in base.ts:205 as a FileUploadError when the first argument does not satisfy isFormData(). The SDK requires a real FormData instance (browser FormData, or a Node FormData-like object exposing append/getHeaders) because the /audio-to-text endpoint consumes multipart/form-data. Passing a plain object, Buffer, ReadStream, or undefined is rejected before any HTTP call is made.
Source
Thrown at sdks/nodejs-client/src/client/base.ts:205
}
filePreview(fileId: string, user: string, asAttachment?: boolean): Promise<DifyResponse<Buffer>> {
ensureNonEmptyString(fileId, 'fileId')
ensureNonEmptyString(user, 'user')
return this.http.request<Buffer, 'bytes'>({
method: 'GET',
path: `/files/${fileId}/preview`,
query: {
user,
as_attachment: asAttachment ? 'true' : undefined,
},
responseType: 'bytes',
})
}
audioToText(form: unknown, user: string): Promise<DifyResponse<JsonObject>> {
if (!isFormData(form)) {
throw new FileUploadError('FormData is required for audio uploads')
}
ensureNonEmptyString(user, 'user')
appendUserToFormData(form, user)
return this.http.request({
method: 'POST',
path: '/audio-to-text',
data: form,
})
}
textToAudio(request: TextToAudioRequest): Promise<DifyResponse<Buffer> | BinaryStream>
textToAudio(
text: string,
user: string,
streaming?: boolean,
voice?: string,
): Promise<DifyResponse<Buffer> | BinaryStream>
textToAudio(View on GitHub (pinned to ef8544b173)
Solutions
- Construct an actual FormData, append the audio file under the field name expected by the server (typically 'file'), then pass it: const form = new FormData(); form.append('file', fileBlob, 'audio.mp3'); await client.audioToText(form, user).
- On Node < 18, install and import a FormData polyfill (e.g. form-data) so isFormData() recognizes it via getHeaders() or constructor.name === 'FormData'.
- Confirm the value is not undefined by building the FormData in the same scope that calls audioToText rather than receiving it from an untyped source.
- If reading from disk in Node, convert the buffer to a Blob/File before appending rather than passing the Buffer as the form argument.
Example fix
// before
await client.audioToText({ file: '/tmp/a.mp3' }, user) // object, not FormData
// after
import FormData from 'form-data'
const form = new FormData()
form.append('file', fs.createReadStream('/tmp/a.mp3'), 'a.mp3')
await client.audioToText(form, user) Defensive patterns
Strategy: type-guard
Validate before calling
import { isFormData } from '@dify-platform/dify-client/src/http/form-data'
function asAudioForm(value: unknown): FormData {
if (!isFormData(value)) throw new Error('audioToText requires a real FormData instance')
return value as FormData
} Type guard
import { isFormData } from '@dify-platform/dify-client/src/http/form-data'
function isUploadableForm(value: unknown): value is FormData {
return isFormData(value)
} Try / catch
try {
await client.audioToText(form, user)
} catch (err) {
if (err instanceof Error && err.name === 'FileUploadError') {
// log form construction issue, surface user-facing message
} else throw err
} Prevention
- Build the FormData in the same function that calls audioToText so the variable's type is obvious.
- On Node < 18, install a form-data polyfill once at process startup.
- Add a unit test asserting isFormData(yourBuilder()) returns true.
When it happens
Trigger: Calling client.audioToText(payload, user) where payload is a JS object literal, a Buffer holding audio bytes, undefined/null, or a form library whose object is not recognized by isFormData() (no getHeaders method and constructor.name !== 'FormData'). The guard at base.ts:204 fails and FileUploadError is thrown synchronously.
Common situations: Migrating from an older SDK that accepted an object with a file path; using form-urlencoded instead of multipart; passing a Node Buffer directly; bundlers shimming FormData incorrectly; Node versions < 18 where global FormData is absent and the caller forgot to import a polyfill.
Related errors
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/1ab6c44d899fb87e.
Report an issue: GitHub.