langgenius/dify · error · ValidationError
text or message_id is required
Error message
text or message_id is required
What it means
Thrown by the object-form overload of textToAudio() in base.ts:252 as a ValidationError. The endpoint needs a source of speech: either free-form text or a previously generated message_id to re-render. When the request object carries neither a non-empty text nor a message_id, the SDK aborts before calling /text-to-audio.
Source
Thrown at sdks/nodejs-client/src/client/base.ts:252
payload = {
text: textOrRequest,
user,
streaming,
}
if (voice) {
payload.voice = voice
}
} else {
payload = { ...textOrRequest }
ensureNonEmptyString(payload.user, 'user')
if (payload.text !== undefined && payload.text !== null) {
ensureNonEmptyString(payload.text, 'text')
}
if (payload.message_id !== undefined && payload.message_id !== null) {
ensureNonEmptyString(payload.message_id, 'messageId')
}
if (!payload.text && !payload.message_id) {
throw new ValidationError('text or message_id is required')
}
payload.streaming = payload.streaming ?? false
}
if (payload.streaming) {
return this.http.requestBinaryStream({
method: 'POST',
path: '/text-to-audio',
data: payload,
})
}
return this.http.request<Buffer, 'bytes'>({
method: 'POST',
path: '/text-to-audio',
data: payload,
responseType: 'bytes',
})View on GitHub (pinned to ef8544b173)
Solutions
- Provide exactly one of text or message_id in the request object: client.textToAudio({ text: 'Hello world', user }).
- If re-rendering prior TTS output, pass the message_id from a prior message response: client.textToAudio({ message_id: msg.id, user }).
- When constructing the payload programmatically, assert at least one field is populated before calling: if (!req.text && !req.message_id) throw ... in your own layer.
- If you intended the positional string form, call client.textToAudio('Hello', user) instead of wrapping text in an object without a key.
Example fix
// before
await client.textToAudio({ user, voice: 'echo' })
// after
await client.textToAudio({ user, voice: 'echo', text: 'Hello world' }) Defensive patterns
Strategy: validation
Validate before calling
function assertTextToAudioRequest(req: { text?: string; message_id?: string; user: string }) {
if (!req.text?.trim() && !req.message_id?.trim()) {
throw new Error('textToAudio requires text or message_id')
}
} Type guard
function hasTextSource(req: unknown): req is { text: string } | { message_id: string } {
if (typeof req !== 'object' || req === null) return false
const r = req as { text?: unknown; message_id?: unknown }
return (typeof r.text === 'string' && r.text.trim().length > 0)
|| (typeof r.message_id === 'string' && r.message_id.trim().length > 0)
} Try / catch
try {
await client.textToAudio(payload)
} catch (err) {
if (err instanceof Error && err.name === 'ValidationError' && /text or message_id/.test(err.message)) {
// prompt user to provide one of the two
} else throw err
} Prevention
- Make the upstream UI require either text or a prior message selection before submit.
- Use the positional string overload (client.textToAudio('text', user)) when you always have text.
- Type your request object so missing fields surface at compile time.
When it happens
Trigger: Calling client.textToAudio({ user }) or client.textToAudio({ text: '', user }) — i.e. the object form where both text and message_id are missing, undefined, null, or empty strings. The check at base.ts:251 (`!payload.text && !payload.message_id`) fires after the per-field optional validators.
Common situations: Building the request payload dynamically and the field that should carry text/message_id was renamed or stripped; copy-pasting a chat request shape expecting message_id to be auto-populated; passing whitespace-only text; treating textToAudio's first arg as positional string while actually passing an object.
Related errors
- ${name} must be a non-empty array
- ${name} must be a non-empty string
- ${name} must be a non-empty string array
- streaming response body missing
- usage_missing_arg
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/072f2c8b180185db.
Report an issue: GitHub.