Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions agent/error_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,7 @@ def _classify_400(
"encrypted content for item" in error_msg
and "could not be verified" in error_msg
)
or "could not decrypt the provided encrypted_content" in error_msg
):
return result_fn(
FailoverReason.invalid_encrypted_content,
Expand Down
20 changes: 20 additions & 0 deletions tests/agent/test_error_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,26 @@ def test_invalid_encrypted_content_classified_as_retryable_replay_failure(self):
assert result.retryable is True
assert result.should_fallback is False

def test_xai_invalid_encrypted_content_wording_uses_replay_recovery(self):
e = MockAPIError(
"Error code: 400 - Could not decrypt the provided encrypted_content. "
"Ensure the value is the unmodified encrypted_content from a previous response.",
status_code=400,
body={
"code": "Client specified an invalid argument",
"error": (
"Could not decrypt the provided encrypted_content. Ensure the value "
"is the unmodified encrypted_content from a previous response."
),
},
)

result = classify_api_error(e, provider="xai-oauth", model="grok-4.3")

assert result.reason == FailoverReason.invalid_encrypted_content
assert result.retryable is True
assert result.should_fallback is False

def test_invalid_encrypted_content_broad_message_match_does_not_catch_generic_parse_error(self):
message = "Encrypted content could not be decrypted or parsed."
e = MockAPIError(
Expand Down
Loading