From f639425ff06db7b5d379d749b6954eeb38d56972 Mon Sep 17 00:00:00 2001 From: pdasgup Date: Thu, 16 Apr 2026 16:21:07 -0700 Subject: [PATCH] add check for none status code in FinishAbort (#22535) Co-authored-by: Xinyuan Tong <115166877+JustinTong0323@users.noreply.github.com> Co-authored-by: hnyls2002 --- .../srt/entrypoints/openai/serving_chat.py | 18 +++++++++++------- .../entrypoints/openai/serving_completions.py | 15 ++++++++++----- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/python/sglang/srt/entrypoints/openai/serving_chat.py b/python/sglang/srt/entrypoints/openai/serving_chat.py index 6646983dc..1173e0b3b 100644 --- a/python/sglang/srt/entrypoints/openai/serving_chat.py +++ b/python/sglang/srt/entrypoints/openai/serving_chat.py @@ -729,11 +729,16 @@ class OpenAIServingChat(OpenAIServingBase): # Track finish_reason for each index if finish_reason_type: - # If the abort is from scheduler. - if finish_reason_type == "abort": - code = finish_reason.get( - "status_code", HTTPStatus.INTERNAL_SERVER_ERROR - ) + # Abort with an explicit error status_code is a system error + # (timeout, OOM, validation): emit a streaming error chunk. + # A graceful abort (no status_code, e.g. user-initiated via + # /abort_request or session lifecycle cleanup) falls through + # to the normal chunk path, matching the non-stream behavior + # in tokenizer_manager._handle_abort_finish_reason. + if finish_reason_type == "abort" and isinstance( + finish_reason.get("status_code"), HTTPStatus + ): + code = finish_reason["status_code"] error = self.create_streaming_error_response( finish_reason.get("message", "Generation aborted."), code.name, @@ -741,8 +746,7 @@ class OpenAIServingChat(OpenAIServingBase): ) yield f"data: {error}\n\n" break - else: - finish_reasons[index] = finish_reason + finish_reasons[index] = finish_reason # First chunk with role if is_firsts.get(index, True): diff --git a/python/sglang/srt/entrypoints/openai/serving_completions.py b/python/sglang/srt/entrypoints/openai/serving_completions.py index 2e963f330..2b80469b6 100644 --- a/python/sglang/srt/entrypoints/openai/serving_completions.py +++ b/python/sglang/srt/entrypoints/openai/serving_completions.py @@ -307,11 +307,16 @@ class OpenAIServingCompletion(OpenAIServingBase): finish_reason = content["meta_info"].get("finish_reason", None) finish_reason_type = finish_reason["type"] if finish_reason else None - # If the abort is from scheduler. - if finish_reason_type == "abort": - code = finish_reason.get( - "status_code", HTTPStatus.INTERNAL_SERVER_ERROR - ) + # Abort with an explicit error status_code is a system error + # (timeout, OOM, validation): emit a streaming error chunk. + # A graceful abort (no status_code, e.g. user-initiated via + # /abort_request or session lifecycle cleanup) falls through + # to the normal chunk path, matching the non-stream behavior + # in tokenizer_manager._handle_abort_finish_reason. + if finish_reason_type == "abort" and isinstance( + finish_reason.get("status_code"), HTTPStatus + ): + code = finish_reason["status_code"] error = self.create_streaming_error_response( finish_reason.get("message", "Generation aborted."), code.name,