{"record":{"id":"fdff66c66d3696ee","repo":"firecrawl/open-lovable","slug":"failed-to-generate-recreation","errorCode":null,"errorMessage":"Failed to generate recreation","messagePattern":"Failed to generate recreation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/generation/page.tsx","lineNumber":3233,"sourceCode":"              : `Successfully recreated ${url} as a modern React app${homeContextInput ? ` with your requested context: \"${homeContextInput}\"` : ''}! The scraped content is now in my context, so you can ask me to modify specific sections or add features based on the original site.`,\n            'ai',\n            {\n              scrapedUrl: url,\n              scrapedContent: brandExtensionMode ? { brandGuidelines } : scrapeData,\n              generatedCode: generatedCode\n            }\n          );\n          \n          setConversationContext(prev => ({\n            ...prev,\n            generatedComponents: [],\n            appliedCode: [...prev.appliedCode, {\n              files: [],\n              timestamp: new Date()\n            }]\n          }));\n        } else {\n          throw new Error('Failed to generate recreation');\n        }\n        \n        setUrlInput('');\n        setUrlStatus([]);\n        setHomeContextInput('');\n        \n        // Clear generation progress and all screenshot/design states\n        setGenerationProgress(prev => ({\n          ...prev,\n          isGenerating: false,\n          isStreaming: false,\n          status: 'Generation complete!'\n        }));\n        \n        // Clear screenshot and preparing design states to prevent them from showing on next run\n        setIsScreenshotLoaded(false); // Reset loaded state\n        setUrlScreenshot(null);\n        setIsPreparingDesign(false);","sourceCodeStart":3215,"sourceCodeEnd":3251,"githubUrl":"https://github.com/firecrawl/open-lovable/blob/69bd93bae7a9c97ef989eb70aabe6797fb3dac89/app/generation/page.tsx#L3215-L3251","documentation":"This error is thrown by AISandboxPage's URL-recreation flow after it finishes consuming the streaming response from /api/generate-ai-code-stream. The stream ended with HTTP 200, but the client never received an SSE event of type 'complete' carrying a non-empty `generatedCode`, so `generatedCode` is still an empty string and the code throws. It is a client-side guard meaning 'the AI backend streamed nothing usable' — the actual failure (model error, mid-stream abort, missing complete event) happened upstream or during SSE parsing.","triggerScenarios":"The SSE stream from POST /api/generate-ai-code-stream closes without ever emitting a `data: {\"type\":\"complete\",\"generatedCode\":...}` event, or the complete event's generatedCode is empty/falsy. Also caused by: SSE JSON lines that fail JSON.parse (silently swallowed by the inner try/catch at line 3185), the server erroring mid-stream, truncated chunks that split a `data:` line across reader.read() boundaries so `line.startsWith('data: ')` never matches the complete event, or the model returning prose with no <file> payload.","commonSituations":"AI provider API key missing/expired or rate-limited server-side so the stream errors mid-way; very long generation timing out and the connection dropping before the complete event; a chunk boundary splitting the final SSE line (the naive `chunk.split('\\n')` parser does not buffer partial lines); model output filtered out by the tag-stripping/filters; deployment where the route handler silently returns an empty stream after an upstream failure.","solutions":["Inspect the server logs / network tab for /api/generate-ai-code-stream to find the real upstream failure (missing AI API key, provider error, quota).","Fix the SSE parser to buffer partial lines across reader.read() chunks before splitting on '\\n', so a complete event split across chunks is not lost.","Log failed JSON.parse events in the inner catch (line 3185-3187) instead of only console.error, to see if the complete event was malformed.","On the server, always emit a final 'complete' (or 'error') SSE event in a finally block so the client never ends a stream without a terminal event.","Add client-side retry: catch this error and re-issue the generation request once before surfacing failure to the user."],"exampleFix":"// before: per-chunk naive parse loses split SSE lines\nconst chunk = decoder.decode(value);\nconst lines = chunk.split('\\n');\nfor (const line of lines) {\n  if (line.startsWith('data: ')) {\n    const data = JSON.parse(line.slice(6));\n    ...\n  }\n}\n\n// after: buffer partial lines so the 'complete' event is never missed\nlet buffer = '';\nwhile (true) {\n  const { done, value } = await reader.read();\n  if (done) break;\n  buffer += decoder.decode(value, { stream: true });\n  const lines = buffer.split('\\n');\n  buffer = lines.pop() ?? '';\n  for (const line of lines) {\n    if (line.startsWith('data: ')) {\n      const data = JSON.parse(line.slice(6));\n      if (data.type === 'complete') generatedCode = data.generatedCode;\n    }\n  }\n}\nif (!generatedCode) throw new Error('Failed to generate recreation');","handlingStrategy":"retry","validationCode":"async function streamHasCompleteEvent(url: string, body: object): Promise<boolean> {\n  const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });\n  if (!res.ok || !res.body) return false;\n  const text = await res.text();\n  return text.split('\\n').some(l => l.startsWith('data: ') && JSON.parse(l.slice(6)).type === 'complete');\n}","typeGuard":"function isCompleteEvent(d: unknown): d is { type: 'complete'; generatedCode: string; explanation?: string } {\n  return typeof d === 'object' && d !== null && (d as any).type === 'complete' && typeof (d as any).generatedCode === 'string' && (d as any).generatedCode.trim().length > 0;\n}","tryCatchPattern":"try {\n  await generateRecreation(url);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Failed to generate recreation') {\n    setGenerationProgress(prev => ({ ...prev, isGenerating: false, isStreaming: false, status: 'Generation failed — retrying...' }));\n    await generateRecreation(url); // single retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Buffer partial SSE lines across read() chunks instead of splitting each decoded chunk on newlines.","Verify the AI provider key/quota is configured in the environment before starting a long generation.","Ensure the server route always emits a terminal 'complete' or 'error' SSE event, even on failure (try/finally).","Log and surface failed JSON.parse of SSE data lines rather than swallowing them.","Treat an empty generatedCode as a distinct UI state (retryable) instead of letting the throw escape as an unhandled promise rejection."],"tags":["streaming","sse","ai-generation","empty-response","react"],"backgroundTag":"ai-stream-returned-empty-response","analyzedSha":"69bd93bae7a9c97ef989eb70aabe6797fb3dac89","analyzedAt":"2026-08-28T22:20:32.339Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}