Mintplex-Labs/anything-llm · warning · Error

No text to predict on.

Error message

No text to predict on.

What it means

Thrown inside the Piper TTS Web Worker: runStream splits the submitted text into synthesis chunks, and when splitIntoChunks returns an empty list the stream cannot start, so this Error is raised. It is pure input validation — PIPER_SESSION.predict is never called and no audio work happens. The error propagates through the worker's error handling rather than any HTTP layer.

Solutions

  1. Guard at the call site: skip TTS entirely when !text.trim().
  2. Inspect what splitIntoChunks strips — if it removes markdown, make sure real prose remains before posting to the worker.
  3. If queueing from the UI, debounce and ignore empty messages instead of posting them to the worker.

Example fix

// before
worker.postMessage({ type: 'stream', streamId, text });

// after
if (!text || !text.trim()) return; // nothing to synthesize
worker.postMessage({ type: 'stream', streamId, text });
Defensive patterns

Strategy: validation

Validate before calling

// run before posting a stream to the piperTTS worker
function hasSpeakableText(text) {
  return typeof text === 'string' && text.trim().length > 0;
}
if (!hasSpeakableText(text)) return; // never enqueue empty/whitespace text

Type guard

/** @param {any} t @returns {t is string} */
function isSpeakable(t) {
  return typeof t === 'string' && t.replace(/\s|[*_`>#-]/g, '').length > 0;
}

Try / catch

self.onerror = (e) => {
  if (/No text to predict on/.test(e.message)) return; // benign — nothing to speak
  postMessage({ type: 'stream-error', message: e.message });
};

Prevention

When it happens

Trigger: Enqueueing TTS for an empty or whitespace-only string; text that is entirely stripped away by the chunking logic (e.g. only markdown/symbols, no speakable prose); a UI race where the stream is posted before the message text is set.

Common situations: Speaking an empty assistant message; message content that reduces to nothing after sanitization; autoplay/speak-on-arrive features firing on placeholder chunks.

Related errors


AI-assisted analysis of Mintplex-Labs/anything-llm@3aec848f28 (2026-08-18). Data as JSON: /api/errors/284327b035c8decb. Report an issue: GitHub.

Appendix: source

Thrown at frontend/src/utils/piperTTS/worker.js:141

      self.postMessage({ type: "error", message: error.message, error }); // Will be an error.
    });
}

/**
 * Renders one streamed prediction. Every message posted back carries the
 * streamId so listeners can ignore chunks that belong to a different stream.
 * @param {string} streamId
 * @param {string} text
 */
async function runStream(streamId, text) {
  try {
    if (ACTIVE_STREAM_ID !== streamId) {
      // Superseded or aborted while waiting in the queue - never started.
      self.postMessage({ type: "stream-end", streamId, aborted: true });
      return;
    }
    const chunks = splitIntoChunks(text);
    if (chunks.length === 0) throw new Error("No text to predict on.");
    self.postMessage({ type: "stream-start", streamId, total: chunks.length });
    for (let i = 0; i < chunks.length; i++) {
      if (ACTIVE_STREAM_ID !== streamId) break;
      const audio = await PIPER_SESSION.predict(chunks[i]);
      if (ACTIVE_STREAM_ID !== streamId) break; // lost ownership mid-predict - drop the stale chunk
      self.postMessage({
        type: "stream-chunk",
        streamId,
        audio,
        index: i,
        total: chunks.length,
      });
    }
    self.postMessage({
      type: "stream-end",
      streamId,
      aborted: ACTIVE_STREAM_ID !== streamId,
    });

View on GitHub (pinned to 3aec848f28)