{"record":{"id":"427e894fd2bed403","repo":"can1357/oh-my-pi","slug":"options-firstitemerrormessage-options-errormess","errorCode":null,"errorMessage":"options.firstItemErrorMessage ?? options.errorMessage","messagePattern":"options\\.firstItemErrorMessage \\?\\? options\\.errorMessage","errorType":"exception","errorClass":"AIError.StreamTimeoutError","httpStatus":null,"severity":"warning","filePath":"packages/ai/src/utils/idle-iterator.ts","lineNumber":337,"sourceCode":"\t\t\t\t\tconst { promise, resolve } = Promise.withResolvers<{ kind: \"abort\" }>();\n\t\t\t\t\tresolveAbort = resolve;\n\t\t\t\t\tabortPromise = promise;\n\t\t\t\t}\n\t\t\t\tif (timeoutPromise !== undefined && !timeoutFired) {\n\t\t\t\t\tconst { promise, resolve } = Promise.withResolvers<{ kind: \"timeout\" }>();\n\t\t\t\t\tresolveTimeout = resolve;\n\t\t\t\t\ttimeoutPromise = promise;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet activeTimeoutMs: number | undefined;\n\t\t\tif (awaitingFirstItem) {\n\t\t\t\tif (firstItemDeadlineMs !== undefined) {\n\t\t\t\t\tactiveTimeoutMs = firstItemDeadlineMs - Date.now();\n\t\t\t\t\tif (activeTimeoutMs <= 0) {\n\t\t\t\t\t\tif (!hasPendingLocalWork()) {\n\t\t\t\t\t\t\toptions.onFirstItemTimeout?.();\n\t\t\t\t\t\t\tcloseIterator();\n\t\t\t\t\t\t\tthrow new AIError.StreamTimeoutError(options.firstItemErrorMessage ?? options.errorMessage);\n\t\t\t\t\t\t}\n\t\t\t\t\t\textendDeadlineForLocalWork();\n\t\t\t\t\t\tactiveTimeoutMs = firstItemDeadlineMs! - Date.now();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (options.idleTimeoutMs !== undefined && options.idleTimeoutMs > 0) {\n\t\t\t\tactiveTimeoutMs = options.idleTimeoutMs - (Date.now() - lastProgressAt);\n\t\t\t\tif (activeTimeoutMs <= 0) {\n\t\t\t\t\tif (!hasPendingLocalWork()) {\n\t\t\t\t\t\toptions.onIdle?.();\n\t\t\t\t\t\tcloseIterator();\n\t\t\t\t\t\tthrow new AIError.StreamTimeoutError(options.errorMessage);\n\t\t\t\t\t}\n\t\t\t\t\textendDeadlineForLocalWork();\n\t\t\t\t\tactiveTimeoutMs = options.idleTimeoutMs;\n\t\t\t\t}\n\t\t\t}\n","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/utils/idle-iterator.ts#L319-L355","documentation":"AIError.StreamTimeoutError thrown by iterateWithIdleTimeout when no first item arrives within options.firstItemDeadlineMs and there is no pending local work. The message comes from options.firstItemErrorMessage ?? options.errorMessage, so callers control the surfaced text. It distinguishes 'provider never started responding' from mid-stream stalls.","triggerScenarios":"Any stream wrapped with iterateWithIdleTimeout (timedAnthropicStream, timedOpenaiStream, chunks, wrapCodexSseStream, watchedSource, run) where the first chunk/association event does not arrive before firstItemDeadlineMs elapses — e.g. slow model time-to-first-token, hung TLS handshake, or a blocked proxy.","commonSituations":"Provider outage or severe latency making time-to-first-token exceed the deadline; network firewall silently dropping the connection; first-item deadline configured too aggressively for a slow/large-prompt request.","solutions":["Increase firstItemDeadlineMs (or use a smaller firstItemErrorMessage-informing deadline) to accommodate model latency.","Set a descriptive options.firstItemErrorMessage so downstream handlers can distinguish start-timeout from idle-timeout.","Use options.onFirstItemTimeout to implement fallback (e.g. retry against a different provider/region).","Check provider status/network path — persistent first-item timeouts indicate connectivity or provider issues, not tuning."],"exampleFix":"// before\niterateWithIdleTimeout(stream, { firstItemDeadlineMs: 2_000, errorMessage: \"stream timeout\" });\n// after\niterateWithIdleTimeout(stream, {\n\tfirstItemDeadlineMs: 30_000,\n\tonFirstItemTimeout: () => scheduleFallback(),\n\tfirstItemErrorMessage: \"no first token within 30s\",\n\terrorMessage: \"stream idle timeout\",\n});","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n\tfor await (const ev of timedStream) handle(ev);\n} catch (err) {\n\tif (err instanceof AIError.StreamTimeoutError) {\n\t\t// first-item timeout: retry once, then fall back to another provider\n\t} else throw err;\n}","preventionTips":["Set firstItemDeadlineMs well above observed p99 time-to-first-token.","Wire onFirstItemTimeout to a fallback provider/region.","Monitor TTFT metrics and adjust the deadline from data."],"tags":["timeout","streaming","network"],"backgroundTag":"stream-first-token-timeout","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}