{"record":{"id":"284327b035c8decb","repo":"Mintplex-Labs/anything-llm","slug":"no-text-to-predict-on","errorCode":null,"errorMessage":"No text to predict on.","messagePattern":"No text to predict on\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/src/utils/piperTTS/worker.js","lineNumber":141,"sourceCode":"      self.postMessage({ type: \"error\", message: error.message, error }); // Will be an error.\n    });\n}\n\n/**\n * Renders one streamed prediction. Every message posted back carries the\n * streamId so listeners can ignore chunks that belong to a different stream.\n * @param {string} streamId\n * @param {string} text\n */\nasync function runStream(streamId, text) {\n  try {\n    if (ACTIVE_STREAM_ID !== streamId) {\n      // Superseded or aborted while waiting in the queue - never started.\n      self.postMessage({ type: \"stream-end\", streamId, aborted: true });\n      return;\n    }\n    const chunks = splitIntoChunks(text);\n    if (chunks.length === 0) throw new Error(\"No text to predict on.\");\n    self.postMessage({ type: \"stream-start\", streamId, total: chunks.length });\n    for (let i = 0; i < chunks.length; i++) {\n      if (ACTIVE_STREAM_ID !== streamId) break;\n      const audio = await PIPER_SESSION.predict(chunks[i]);\n      if (ACTIVE_STREAM_ID !== streamId) break; // lost ownership mid-predict - drop the stale chunk\n      self.postMessage({\n        type: \"stream-chunk\",\n        streamId,\n        audio,\n        index: i,\n        total: chunks.length,\n      });\n    }\n    self.postMessage({\n      type: \"stream-end\",\n      streamId,\n      aborted: ACTIVE_STREAM_ID !== streamId,\n    });","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/526360e320da9d1b36074be5ed64fe76e5bbfbbd/frontend/src/utils/piperTTS/worker.js#L123-L159","documentation":"Thrown inside the Piper TTS Web Worker when splitIntoChunks(text) returns an empty array, meaning there is no speakable content. The worker runs predictions chunk-by-chunk against PIPER_SESSION.predict; with zero chunks there is nothing to synthesize, so it throws before posting stream-start. The catch posts an { type: 'error', streamId, message } back to the main thread.","triggerScenarios":"Calling the worker's runStream with an empty string, a string that is only whitespace/punctuation that splitIntoChunks strips, or calling runStream after SSML/markdown sanitization removed all tokens.","commonSituations":"TTS triggered on a chat message that contains only an image or code block (no prose); user clicked 'speak' on an empty input; upstream text sanitizer over-aggressively removed punctuation-only runs; clipboard paste of whitespace-only content.","solutions":["Trim and check the text is non-empty (has at least one alphanumeric character) before posting the message to the worker.","Adjust splitIntoChunks so it treats punctuation-only input as content rather than dropping it.","In the main thread, ignore the worker's 'error' message when the message field is 'No text to predict on.' since it is benign."],"exampleFix":"// before — caller posts unconditionally\nworker.postMessage({ type: 'stream-start', streamId, text });\n\n// after — guard empty text in the caller\nconst speakable = text.trim();\nif (!speakable) return;\nworker.postMessage({ type: 'stream-start', streamId, text: speakable });","handlingStrategy":"validation","validationCode":"// Only post to the TTS worker if there is speakable text.\nfunction hasSpeakableText(text) {\n  return typeof text === 'string' && /\\S/.test(text.replace(/[\\s\\p{P}]/gu, ''));\n}","typeGuard":null,"tryCatchPattern":"// In the worker, downgrade empty-text to a benign stream-end rather than an error.\nif (chunks.length === 0) {\n  self.postMessage({ type: 'stream-end', streamId, aborted: true });\n  return;\n}","preventionTips":["Trim and check for at least one alphanumeric character before invoking TTS.","Treat punctuation-only input as content or skip silently rather than erroring.","Ignore the worker's 'No text to predict on.' error on the main thread since it is benign."],"tags":["frontend","web-worker","tts","piper","validation"],"backgroundTag":null,"analyzedSha":"526360e320da9d1b36074be5ed64fe76e5bbfbbd","analyzedAt":"2026-08-13T01:45:47.170Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}