mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
Stop retrying explicit invalid-workspace errors (#60475)
## Why HTTP 403 responses with `invalid_workspace_selected` were treated as unexpected status errors, allowing retries and compaction fallback to another model after the server rejected the selected workspace. ## What changed Recognize the code in `detail.code` or `error.code`, falling back to the `x-error-json` header when the body has no code. Classify these 403 responses as `InvalidWorkspaceSelected` and disable retries and compaction model fallback while preserving the response details and HTTP status. Other 403 responses retain their existing retry behavior. ## Testing Add coverage for body and header error codes, code precedence, HTTP and WebSocket retry behavior, and local and remote compaction during a model downshift. GitOrigin-RevId: f44a3bee5ef06e601909839868ab99cea6dd7d03
This commit is contained in:
@@ -148,6 +148,9 @@ pub enum CodexErrorDetails {
|
||||
/// surface a polite FunctionCallOutput back to the model instead of crashing the CLI.
|
||||
#[error("interrupted (Ctrl-C). Something went wrong? Hit `/feedback` to report the issue.")]
|
||||
Interrupted,
|
||||
/// The server rejected the selected workspace.
|
||||
#[error("{0}")]
|
||||
InvalidWorkspaceSelected(UnexpectedResponseError),
|
||||
/// Unexpected HTTP status code.
|
||||
#[error("{0}")]
|
||||
UnexpectedStatus(UnexpectedResponseError),
|
||||
@@ -466,6 +469,7 @@ impl CodexErr {
|
||||
| CodexErrorDetails::FlexUnavailable
|
||||
| CodexErrorDetails::CyberPolicy { .. }
|
||||
| CodexErrorDetails::BioPolicy { .. }
|
||||
| CodexErrorDetails::InvalidWorkspaceSelected(_)
|
||||
| CodexErrorDetails::MisalignmentPolicyViolation { .. } => None,
|
||||
CodexErrorDetails::ServerOverloaded
|
||||
| CodexErrorDetails::PolicyCapacityUnavailable
|
||||
@@ -539,11 +543,11 @@ impl CodexErr {
|
||||
CodexErrorDetails::RetryLimit(_) => CodexErrorInfo::ResponseTooManyFailedAttempts {
|
||||
http_status_code: self.http_status_code_value(),
|
||||
},
|
||||
CodexErrorDetails::ConnectionFailed(_) | CodexErrorDetails::UnexpectedStatus(_) => {
|
||||
CodexErrorInfo::HttpConnectionFailed {
|
||||
http_status_code: self.http_status_code_value(),
|
||||
}
|
||||
}
|
||||
CodexErrorDetails::ConnectionFailed(_)
|
||||
| CodexErrorDetails::InvalidWorkspaceSelected(_)
|
||||
| CodexErrorDetails::UnexpectedStatus(_) => CodexErrorInfo::HttpConnectionFailed {
|
||||
http_status_code: self.http_status_code_value(),
|
||||
},
|
||||
CodexErrorDetails::ResponseStreamFailed(_) => {
|
||||
CodexErrorInfo::ResponseStreamConnectionFailed {
|
||||
http_status_code: self.http_status_code_value(),
|
||||
@@ -586,7 +590,8 @@ impl CodexErr {
|
||||
CodexErrorDetails::FlexUnavailable => Some(StatusCode::TOO_MANY_REQUESTS),
|
||||
CodexErrorDetails::ModelNotFound { status, .. } => *status,
|
||||
CodexErrorDetails::RetryLimit(err) => Some(err.status),
|
||||
CodexErrorDetails::UnexpectedStatus(err) => Some(err.status),
|
||||
CodexErrorDetails::InvalidWorkspaceSelected(err)
|
||||
| CodexErrorDetails::UnexpectedStatus(err) => Some(err.status),
|
||||
CodexErrorDetails::ConnectionFailed(err) => err.source.status(),
|
||||
CodexErrorDetails::ResponseStreamFailed(err) => err.source.status(),
|
||||
_ => None,
|
||||
|
||||
Reference in New Issue
Block a user