{"record":{"id":"9f896bc4acc5a2e4","repo":"sigoden/aichat","slug":"err-9f896b","errorCode":null,"errorMessage":"{err}","messagePattern":"\\{err\\}","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/serve.rs","lineNumber":413,"sourceCode":"                    handler.done();\n                }\n                tokio::join!(\n                    map_event(sse_rx, &tx, is_first.clone()),\n                    chat_completions(\n                        client.as_ref(),\n                        &http_client,\n                        &mut handler,\n                        data,\n                        &tx,\n                        is_first\n                    ),\n                );\n            });\n\n            let first_event = rx.recv().await;\n\n            if let Some(ResEvent::First(Some(err))) = first_event {\n                bail!(\"{err}\");\n            }\n\n            let shared: Arc<(String, String, i64, AtomicBool)> =\n                Arc::new((completion_id, model_name, created, AtomicBool::new(false)));\n            let stream = UnboundedReceiverStream::new(rx);\n            let stream = stream.filter_map(move |res_event| {\n                let shared = shared.clone();\n                async move {\n                    let (completion_id, model, created, has_tool_calls) = shared.as_ref();\n                    match res_event {\n                        ResEvent::Text(text) => {\n                            Some(Ok(create_text_frame(completion_id, model, *created, &text)))\n                        }\n                        ResEvent::ToolCalls(tool_calls) => {\n                            has_tool_calls.store(true, Ordering::SeqCst);\n                            Some(Ok(create_tool_calls_frame(\n                                completion_id,\n                                model,","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/sigoden/aichat/blob/82976d349ad97ac9aae0655ad631dace5e2a6385/src/serve.rs#L395-L431","documentation":"During streaming chat completions, the upstream provider/channel pushes an error as the first stream event (ResEvent::First(Some(err))). The server aborts the request with bail!(\"{err}\"), surfacing the underlying provider error to the client before any content is streamed.","triggerScenarios":"Calling POST /v1/chat/completions with stream=true when the first event received on the channel is an error (e.g. the provider rejected the request, auth failed, or model unavailable).","commonSituations":"Upstream API key invalid or expired; selected model not available on the provider; provider returns an immediate error for the request body; proxy/channel misconfiguration.","solutions":["Read the interpolated message for the underlying provider error and fix that root cause first","Verify the provider API key/credentials configured for the model's channel","Confirm the requested model name exists on the provider","Retry with a non-streaming request to get a clearer error payload","Switch to a different provider/channel to isolate whether it is provider-side"],"exampleFix":"// before: err message obscures root cause\nbail!(\"{err}\");\n// after: log full context and re-raise\nerror!(\"upstream first-event error: {err}\");\nbail!(\"{err}\");","handlingStrategy":"try-catch","validationCode":"// before calling: verify provider config\nif (!apiKey || !model) throw new Error('missing model or apiKey');","typeGuard":null,"tryCatchPattern":"try {\n  const stream = await client.chat.completions.create({ model, messages, stream: true });\n} catch (e) {\n  // message is the upstream provider error; inspect and map\n  console.error('upstream stream error:', e.message);\n}","preventionTips":["Validate provider credentials at startup","Check model availability before streaming","Keep a fallback provider/channel configured"],"tags":["streaming","upstream","chat-completions","openai-api"],"backgroundTag":"upstream-api-error","analyzedSha":"82976d349ad97ac9aae0655ad631dace5e2a6385","analyzedAt":"2026-09-09T18:33:06.139Z","contentChangedAt":"2026-09-09T18:33:06.139Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}