danny-avila/LibreChat · error

Text is required

Error message

Text is required

What it means

Thrown by splitTextIntoChunks in the TTS audio streaming path (streamAudio.js) when the input text is falsy. The chunker is the gate before audio synthesis, so it refuses to operate on empty/null/undefined input rather than send a malformed request to the TTS provider.

Source

Thrown at api/server/services/Files/Audio/streamAudio.js:145

    } else if (complete && remainingText.trim().length > 0) {
      chunks.push({ text: remainingText.trim(), isFinished: true });
      processedText = text;
    }

    return chunks;
  }

  return processChunks;
}

/**
 * @param {string} text
 * @param {number} [chunkSize=4000]
 * @returns {{ text: string, isFinished: boolean }[]}
 */
function splitTextIntoChunks(text, chunkSize = 4000) {
  if (!text) {
    throw new Error('Text is required');
  }

  const chunks = [];
  let startIndex = 0;
  const textLength = text.length;

  while (startIndex < textLength) {
    let endIndex = Math.min(startIndex + chunkSize, textLength);
    let chunkText = text.slice(startIndex, endIndex);

    if (endIndex < textLength) {
      let lastSeparatorIndex = -1;
      for (const separator of SEPARATORS) {
        const index = chunkText.lastIndexOf(separator);
        if (index !== -1) {
          lastSeparatorIndex = Math.max(lastSeparatorIndex, index);
        }
      }

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Validate that the message has non-empty text before invoking the TTS/streamAudio path (guard at the controller/route level).
  2. Coalesce falsy text to a safe default or short-circuit the request with a 400 when text is empty.
  3. Trace the caller of splitTextIntoChunks to confirm the text source (message content) is populated before the call.

Example fix

// before
const chunks = splitTextIntoChunks(text);

// after
if (!text || !text.trim()) {
  return res.status(400).json({ message: 'Text is required' });
}
const chunks = splitTextIntoChunks(text);
Defensive patterns

Strategy: validation

Validate before calling

// Before calling the TTS/streamAudio pipeline
function hasSpeakableText(text) {
  return typeof text === 'string' && text.trim().length > 0;
}

if (!hasSpeakableText(message?.text)) {
  return res.status(400).json({ message: 'Text is required' });
}
splitTextIntoChunks(message.text);

Type guard

/** @param {unknown} t @returns {t is string} */
function isNonEmptyString(t) {
  return typeof t === 'string' && t.trim().length > 0;
}

Try / catch

try {
  const chunks = splitTextIntoChunks(text);
} catch (err) {
  if (/Text is required/.test(err.message)) {
    return res.status(400).json({ message: 'Cannot synthesize empty text' });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling splitTextIntoChunks(text) (directly or via the streamAudio pipeline) where text is '', null, undefined, 0, or NaN. The guard is a bare `if (!text)` truthiness check, so any falsy value trips it.

Common situations: A TTS request fired for an empty assistant message; upstream message text resolved to undefined because the message wasn't fetched yet; a tool call produced no textual output but still triggered speech.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/f64fdfe84a3cc16c. Report an issue: GitHub.