{"record":{"id":"0690ef79771a9280","repo":"GitbookIO/gitbook","slug":"no-response-found","errorCode":null,"errorMessage":"No response found","messagePattern":"No response found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/gitbook/src/components/AI/server-actions/api.tsx","lineNumber":165,"sourceCode":"\n    const stream = new EventIterator<T>((queue) => {\n        (async () => {\n            let foundResponse = false;\n\n            for await (const event of responseStream) {\n                const parsed = await parse(event);\n                if (parsed !== undefined) {\n                    queue.push(parsed);\n                }\n\n                if (event.type === 'response_finish') {\n                    foundResponse = true;\n                    resolveResponse({ responseId: event.response.id ?? null });\n                }\n            }\n\n            if (!foundResponse) {\n                throw new Error('No response found');\n            }\n        })().then(\n            () => {\n                queue.stop();\n            },\n            (error) => {\n                queue.fail(error);\n            }\n        );\n    });\n\n    return { stream, response };\n}\n","sourceCodeStart":147,"sourceCodeEnd":179,"githubUrl":"https://github.com/GitbookIO/gitbook/blob/db67585ee243d063c459a855988f21612cea9c95/packages/gitbook/src/components/AI/server-actions/api.tsx#L147-L179","documentation":"Thrown inside streamRenderAIMessage's parseResponse helper in the GitBook AI server actions when an AI stream from the API finishes without ever emitting a response_finish event. parseResponse iterates the whole EventIterator looking for that event to capture the responseId; if the stream ends (or errors upstream) without it, the response Promise rejects with 'No response found' and the derived stream is failed with the same error.","triggerScenarios":"Calling streamRenderAIMessage and awaiting its response promise when the upstream API stream closes without a response_finish event; the API returns an immediate error/disconnect event that terminates the iterator early; a network interruption or proxy timeout between the Next.js server and the GitBook API ends the SSE stream prematurely; API schema changes rename or drop the response_finish event type.","commonSituations":"Transient network failures or Cloudflare/edge timeouts severing long AI streams; the AI feature being mid-rollout on the API side so streams end abruptly; using a stale API client whose event type names no longer match what the backend emits.","solutions":["Retry the render call: this most often reflects a dropped stream, so wrap the await in a retry with backoff.","Inspect the raw stream events (log every event.type) to confirm whether any event arrives at all, distinguishing an auth/permission failure from a network drop.","Check that the organization/site actually has AI enabled and the request context (orgId, siteId, URL data) is correct so the API opens a real stream.","If it persists, update the client/API versions — a mismatch between expected and emitted event types causes exactly this silent end-of-stream."],"exampleFix":"// before\nconst { stream, response } = streamRenderAIMessage(...);\nconst { responseId } = await response; // throws 'No response found'\n\n// after\nconst { stream, response } = streamRenderAIMessage(...);\nconst { responseId } = await response.catch((error) => {\n    if (error.message === 'No response found') {\n        return { responseId: null }; // degrade gracefully, stream content may still be usable\n    }\n    throw error;\n});","handlingStrategy":"retry","validationCode":"// Cannot validate before the call (depends on upstream stream health); guard usage instead:\n// only call streamRenderAIMessage when AI is enabled and the context is valid.","typeGuard":null,"tryCatchPattern":"const { stream, response } = streamRenderAIMessage(...);\nconst { responseId } = await response.catch((error) => {\n    if (error instanceof Error && error.message === 'No response found') {\n        return { responseId: null };\n    }\n    throw error;\n});","preventionTips":["Treat responseId as optional; the content stream may still be complete.","Retry once with backoff — dropped streams are usually transient.","Log the raw event types of the stream when debugging to distinguish an empty stream from an early error event."],"tags":["ai","streaming","server-action","network","gitbook"],"backgroundTag":"stream-ended-prematurely","analyzedSha":"db67585ee243d063c459a855988f21612cea9c95","analyzedAt":"2026-08-28T17:49:47.831Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}