@@ -677,6 +677,11 @@ export async function handleUnifiedChatPost(req: NextRequest) {
677677 activeOtelRoot . context
678678 )
679679 if ( branch instanceof NextResponse ) {
680+ // Non-actionable 4xx (400 bad-request from resolveBranch): stamp
681+ // outcome=error for dashboards but leave span status UNSET so
682+ // error alerts don't fire on normal validation rejections.
683+ activeOtelRoot . span . setAttribute ( TraceAttr . HttpStatusCode , branch . status )
684+ activeOtelRoot . finish ( 'error' )
680685 return branch
681686 }
682687
@@ -711,6 +716,8 @@ export async function handleUnifiedChatPost(req: NextRequest) {
711716 : [ ]
712717
713718 if ( body . chatId && ! currentChat ) {
719+ activeOtelRoot . span . setAttribute ( TraceAttr . HttpStatusCode , 404 )
720+ activeOtelRoot . finish ( 'error' )
714721 return NextResponse . json ( { error : 'Chat not found' } , { status : 404 } )
715722 }
716723 }
@@ -733,6 +740,14 @@ export async function handleUnifiedChatPost(req: NextRequest) {
733740 pendingStreamWaitMs = Date . now ( ) - lockStart
734741 if ( ! chatStreamLockAcquired ) {
735742 const activeStreamId = await getPendingChatStreamId ( actualChatId )
743+ // 409 is in the actionable set (see `isActionableErrorStatus`);
744+ // pass a synthesized Error so the span escalates to ERROR status
745+ // and surfaces on pending-stream-collision dashboards.
746+ activeOtelRoot . span . setAttribute ( TraceAttr . HttpStatusCode , 409 )
747+ activeOtelRoot . finish (
748+ 'error' ,
749+ new Error ( 'A response is already in progress for this chat.' )
750+ )
736751 return NextResponse . json (
737752 {
738753 error : 'A response is already in progress for this chat.' ,
0 commit comments