{"record":{"id":"c04aff3a9f37a724","repo":"danielmiessler/Fabric","slug":"streaming-blocked","errorCode":"STREAMING_BLOCKED","errorMessage":"Message submission blocked - already streaming","messagePattern":"Message submission blocked - already streaming","errorType":"exception","errorClass":"ChatError","httpStatus":null,"severity":"warning","filePath":"web/src/lib/store/chat-store.ts","lineNumber":94,"sourceCode":"};\n\nexport async function sendMessage(\n\tcontent: string,\n\tsystemPromptText?: string,\n\tisSystem: boolean = false,\n) {\n\ttry {\n\t\tconsole.log(\"\\n=== Message Processing Start ===\");\n\t\tconsole.log(\"1. Initial state:\", {\n\t\t\tisSystem,\n\t\t\thasSystemPrompt: !!systemPromptText,\n\t\t\tcurrentLanguage: get(languageStore),\n\t\t\tpattern: get(selectedPatternName),\n\t\t});\n\n\t\tconst $streaming = get(streamingStore);\n\t\tif ($streaming) {\n\t\t\tthrow new ChatError(\n\t\t\t\t\"Message submission blocked - already streaming\",\n\t\t\t\t\"STREAMING_BLOCKED\",\n\t\t\t);\n\t\t}\n\n\t\tstreamingStore.set(true);\n\t\terrorStore.set(null);\n\n\t\t// Add message\n\t\tmessageStore.update((messages) => [\n\t\t\t...messages,\n\t\t\t{\n\t\t\t\trole: isSystem ? \"system\" : \"user\",\n\t\t\t\tcontent,\n\t\t\t},\n\t\t]);\n\n\t\tconsole.log(\"2. Message added:\", {","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/store/chat-store.ts#L76-L112","documentation":"The chat store refuses a new submission when streamingStore is already true, throwing ChatError('Message submission blocked - already streaming', 'STREAMING_BLOCKED'). This is an intentional reentrancy guard, not a malfunction: it prevents concurrent /api/chat streams from interleaving into the same message list.","triggerScenarios":"User double-clicks send, presses Enter twice quickly, or an automated flow submits while a previous generation is still streaming and the UI did not disable the submit control.","commonSituations":"Send button not disabled during streaming; keyboard shortcut firing twice; a stuck streamingStore=true after an earlier stream errored without resetting the flag.","solutions":["Disable the send control while $streaming is true in the UI","If it fires with no visible stream, an earlier error path left streamingStore true — ensure every catch/finally resets it","Treat this error as benign in UI code: ignore or toast 'already streaming' rather than showing a generic failure"],"exampleFix":"// before\n<button on:click={() => processMessage(text)}>Send</button>\n\n// after\n<button disabled={$streaming} on:click={() => processMessage(text)}>Send</button>","handlingStrategy":"validation","validationCode":"import { get } from 'svelte/store';\nif (get(streamingStore)) {\n  toast.info('Still generating the previous reply');\n  return; // no throw needed at the call site\n}","typeGuard":"function isStreamingBlocked(e: unknown): e is ChatError & { code: 'STREAMING_BLOCKED' } {\n  return e instanceof ChatError && e.code === 'STREAMING_BLOCKED';\n}","tryCatchPattern":"try { await processMessage(text); }\ncatch (e) {\n  if (isStreamingBlocked(e)) return; // benign: ignore silently\n  throw e;\n}","preventionTips":["Disable the send button and Enter handler while $streaming is true","Reset streamingStore in a finally block so error paths never strand it true","Debounce the submit handler"],"tags":["chat","state-management","reentrancy","ui"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}