mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
Treat invalid access program stream errors as terminal (#60481)
## Why An `invalid_access_program` or `unsupported_access_program` streaming error should end the stream immediately, even if a later `response.completed` event arrives or the error includes a retry header. ## What changed Map both error codes to `ApiError::InvalidRequest` and stop processing the response stream on invalid requests. Preserve a nonblank provider message, falling back to an explanation that the requested access program cannot be used with the model. ## Testing Extend the terminal-error test to cover both codes in `error` and `response.failed` events, verifying that retry headers are ignored and the stream ends before a later completion event. GitOrigin-RevId: 5431a2babec64eae5cdf6c138b98e91e84778e79
This commit is contained in:
@@ -91,13 +91,22 @@ pub(crate) fn parse_terminal_provider_error(
|
||||
) -> Option<ApiError> {
|
||||
let error = error?;
|
||||
let code = error.get("code")?.as_str()?;
|
||||
let message = error
|
||||
.get("message")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|message| !message.trim().is_empty());
|
||||
match (code, status) {
|
||||
// A non-streaming 400 already follows the ordinary invalid-request path.
|
||||
("invalid_access_program" | "unsupported_access_program", None) => {
|
||||
Some(ApiError::InvalidRequest {
|
||||
message: message
|
||||
.unwrap_or("The requested access program cannot be used with this model.")
|
||||
.to_owned(),
|
||||
})
|
||||
}
|
||||
("content_policy_violation", None | Some(StatusCode::BAD_REQUEST)) => {
|
||||
Some(ApiError::ContentPolicyViolation {
|
||||
message: error
|
||||
.get("message")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|message| !message.trim().is_empty())
|
||||
message: message
|
||||
.unwrap_or("The input was rejected by the content policy.")
|
||||
.to_owned(),
|
||||
status,
|
||||
@@ -105,10 +114,7 @@ pub(crate) fn parse_terminal_provider_error(
|
||||
}
|
||||
// HTTP 403s retain their request ID and headers in the API bridge.
|
||||
("access_program_not_enabled", None) => Some(ApiError::AccessProgramNotEnabled {
|
||||
message: error
|
||||
.get("message")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|message| !message.trim().is_empty())
|
||||
message: message
|
||||
.unwrap_or("The requested access program is not enabled.")
|
||||
.to_owned(),
|
||||
}),
|
||||
@@ -125,12 +131,7 @@ pub(crate) fn parse_terminal_provider_error(
|
||||
None | Some(StatusCode::BAD_REQUEST),
|
||||
) => Some(ApiError::InvalidAudioInput {
|
||||
per_recording: code != "audio_too_large",
|
||||
message: error
|
||||
.get("message")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|message| !message.trim().is_empty())
|
||||
.unwrap_or("Invalid audio input.")
|
||||
.to_owned(),
|
||||
message: message.unwrap_or("Invalid audio input.").to_owned(),
|
||||
}),
|
||||
("flex_unavailable", None | Some(StatusCode::TOO_MANY_REQUESTS)) => {
|
||||
Some(ApiError::FlexUnavailable)
|
||||
@@ -139,12 +140,7 @@ pub(crate) fn parse_terminal_provider_error(
|
||||
"model_not_found",
|
||||
None | Some(StatusCode::BAD_REQUEST | StatusCode::FORBIDDEN | StatusCode::NOT_FOUND),
|
||||
) => Some(ApiError::ModelNotFound {
|
||||
message: error
|
||||
.get("message")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|message| !message.trim().is_empty())
|
||||
.unwrap_or(code)
|
||||
.to_owned(),
|
||||
message: message.unwrap_or(code).to_owned(),
|
||||
status,
|
||||
}),
|
||||
_ => None,
|
||||
|
||||
@@ -680,6 +680,7 @@ async fn process_sse_with_treatment(
|
||||
if matches!(
|
||||
error,
|
||||
ApiError::FlexUnavailable
|
||||
| ApiError::InvalidRequest { .. }
|
||||
| ApiError::SessionBudgetExceeded
|
||||
| ApiError::AccessProgramNotEnabled { .. }
|
||||
| ApiError::ContentPolicyViolation { .. }
|
||||
|
||||
@@ -115,6 +115,8 @@ async fn terminal_failure_with_retry_header_ends_stream_immediately() {
|
||||
for (code, expected) in [
|
||||
("flex_unavailable", CodexErrorInfo::FlexUnavailable),
|
||||
("budget_reached", CodexErrorInfo::SessionBudgetExceeded),
|
||||
("invalid_access_program", CodexErrorInfo::Other),
|
||||
("unsupported_access_program", CodexErrorInfo::Other),
|
||||
("content_policy_violation", CodexErrorInfo::InvalidPrompt),
|
||||
(
|
||||
"access_program_not_enabled",
|
||||
|
||||
Reference in New Issue
Block a user