fix(proxy): clarify Codex 413 error as upstream limit, not local proxy

An upstream gateway (e.g. nginx client_max_body_size) rejecting an oversized request body with HTTP 413 was wrapped as "CC Switch local proxy failed ..." with the full nginx HTML page echoed as the cause. This misled users into thinking CC Switch imposed the limit, when the local DefaultBodyLimit is already 200MB and the real cap lives on the provider's server.

413 now gets a dedicated message that points at the upstream gateway, states it is the provider's server-side limit (not CC Switch), and gives actionable recovery steps (/compact, drop large logs/images, ask the provider to raise its limit). Structured fields (upstream_status, provider, model, endpoint) are preserved; other error paths are unchanged.

Refs #666
This commit is contained in:
Jason
2026-06-04 09:44:34 +08:00
parent 084857ce25
commit f5acef32fd
+65 -13
View File
@@ -1005,19 +1005,39 @@ fn codex_proxy_error_json(
return body;
};
let cause = error_obj
.get("message")
.and_then(|value| value.as_str())
.map(ToString::to_string)
.filter(|message| !message.trim().is_empty())
.unwrap_or_else(|| get_error_message(error));
let status_fragment = upstream_status
.map(|status| format!("; upstream_status: HTTP {status}"))
.unwrap_or_default();
let message = format!(
"CC Switch local proxy failed while handling Codex endpoint {endpoint}. Provider: {provider_name}; model: {request_model}{status_fragment}; cause: {cause}"
);
let message = if upstream_status == Some(413) {
// 413 来自上游渠道商的网关(典型是 nginx 的 client_max_body_size),不是 CC
// Switch 本地代理的限制(本地 DefaultBodyLimit 已放到 200MB)。上游响应体往往是
// 一整段 nginx HTML,对用户毫无价值,这里替换成明确指向上游 + 可操作的指引,
// 避免「以为是 CC Switch 封装了 nginx / 是本地代理的锅」这种反复出现的误解。
format!(
concat!(
"Upstream provider rejected the request with HTTP 413 (Payload Too Large). ",
"The request body exceeds the upstream gateway's size limit; this is the ",
"provider's server-side limit, not a CC Switch limit. ",
"Provider: {provider}; model: {model}; endpoint: {endpoint}. ",
"To recover, shrink the request: run /compact, remove large pasted logs or ",
"inline images, or ask the provider to raise its request body limit ",
"(e.g. nginx client_max_body_size)."
),
provider = provider_name,
model = request_model,
endpoint = endpoint,
)
} else {
let cause = error_obj
.get("message")
.and_then(|value| value.as_str())
.map(ToString::to_string)
.filter(|message| !message.trim().is_empty())
.unwrap_or_else(|| get_error_message(error));
let status_fragment = upstream_status
.map(|status| format!("; upstream_status: HTTP {status}"))
.unwrap_or_default();
format!(
"CC Switch local proxy failed while handling Codex endpoint {endpoint}. Provider: {provider_name}; model: {request_model}{status_fragment}; cause: {cause}"
)
};
error_obj.insert(
"message".to_string(),
@@ -1477,4 +1497,36 @@ data: {\"type\":\"response.output_item.done\",\"item\":{\"type\":\"message\"}}\n
assert_eq!(body["error"]["code"], 2013);
assert_eq!(body["error"]["upstream_status"], 502);
}
#[test]
fn codex_proxy_413_points_to_upstream_not_local_proxy() {
// 模拟上游渠道商 nginx 因 client_max_body_size 返回的 413 HTML 页面
// (见 issue #666:长上下文 / 大图 / 大日志撞上游体积上限)
let error = ProxyError::UpstreamError {
status: 413,
body: Some(
"<html>\r\n<head><title>413 Request Entity Too Large</title></head>\r\n\
<body>\r\n<center><h1>413 Request Entity Too Large</h1></center>\r\n\
<hr><center>nginx/1.29.6</center>\r\n</body>\r\n</html>"
.to_string(),
),
};
let body = codex_proxy_error_json("HCAI", "gpt-5.5", "/responses", &error);
let message = body["error"]["message"].as_str().unwrap();
// 不再误导成「本地代理失败」
assert!(!message.contains("CC Switch local proxy failed"));
// 明确指向上游 + 体积超限 + 可操作指引
assert!(message.contains("413"));
assert!(message.to_lowercase().contains("upstream"));
assert!(message.contains("/compact"));
// 关键:不把整段 nginx HTML 回显给用户
assert!(!message.contains("<html>"));
assert!(!message.contains("nginx/1.29.6"));
// 结构化字段仍然保留,便于程序化消费 / UI 呈现
assert_eq!(body["error"]["upstream_status"], 413);
assert_eq!(body["error"]["provider"], "HCAI");
assert_eq!(body["error"]["model"], "gpt-5.5");
assert_eq!(body["error"]["endpoint"], "/responses");
}
}