{"record":{"id":"072f2c8b180185db","repo":"langgenius/dify","slug":"text-or-message-id-is-required","errorCode":null,"errorMessage":"text or message_id is required","messagePattern":"text or message_id is required","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"sdks/nodejs-client/src/client/base.ts","lineNumber":252,"sourceCode":"      payload = {\n        text: textOrRequest,\n        user,\n        streaming,\n      }\n      if (voice) {\n        payload.voice = voice\n      }\n    } else {\n      payload = { ...textOrRequest }\n      ensureNonEmptyString(payload.user, 'user')\n      if (payload.text !== undefined && payload.text !== null) {\n        ensureNonEmptyString(payload.text, 'text')\n      }\n      if (payload.message_id !== undefined && payload.message_id !== null) {\n        ensureNonEmptyString(payload.message_id, 'messageId')\n      }\n      if (!payload.text && !payload.message_id) {\n        throw new ValidationError('text or message_id is required')\n      }\n      payload.streaming = payload.streaming ?? false\n    }\n\n    if (payload.streaming) {\n      return this.http.requestBinaryStream({\n        method: 'POST',\n        path: '/text-to-audio',\n        data: payload,\n      })\n    }\n\n    return this.http.request<Buffer, 'bytes'>({\n      method: 'POST',\n      path: '/text-to-audio',\n      data: payload,\n      responseType: 'bytes',\n    })","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/sdks/nodejs-client/src/client/base.ts#L234-L270","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait client.textToAudio({ user, voice: 'echo' })\n\n// after\nawait client.textToAudio({ user, voice: 'echo', text: 'Hello world' })","handlingStrategy":"validation","validationCode":"function assertTextToAudioRequest(req: { text?: string; message_id?: string; user: string }) {\n  if (!req.text?.trim() && !req.message_id?.trim()) {\n    throw new Error('textToAudio requires text or message_id')\n  }\n}","typeGuard":"function hasTextSource(req: unknown): req is { text: string } | { message_id: string } {\n  if (typeof req !== 'object' || req === null) return false\n  const r = req as { text?: unknown; message_id?: unknown }\n  return (typeof r.text === 'string' && r.text.trim().length > 0)\n    || (typeof r.message_id === 'string' && r.message_id.trim().length > 0)\n}","tryCatchPattern":"try {\n  await client.textToAudio(payload)\n} catch (err) {\n  if (err instanceof Error && err.name === 'ValidationError' && /text or message_id/.test(err.message)) {\n    // prompt user to provide one of the two\n  } else throw err\n}","preventionTips":["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."],"tags":["validation","tts","text-to-audio","required-field"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}