Codex 422 Unprocessable Entity 参数错误处理
Codex 422 Unprocessable Entity 参数错误处理
Codex 接口返回 422 Unprocessable Entity,通常不是网络断了,也不是鉴权失败,而是请求已经被服务端接收,但请求体里的某些参数不符合接口要求。实际排查时,不要一上来改模型、换 SDK,先把完整请求体和响应体打印出来,重点看 model、input、messages、tools、temperature 这类字段。
错误现象
比较常见的现象是本地代码调用失败,HTTP 状态码为 422,响应里带有类似下面的信息:
### token云桥中转 0029.org ###
{
"error": {
"message": "Invalid request body",
"type": "invalid_request_error",
"param": "input",
"code": "unprocessable_entity"
}
}
也可能日志里只看到一句:
HTTP/1.1 422 Unprocessable Entity
如果你使用的是 Node、Python SDK,异常会被包装一层,看起来像 SDK 报错。这个时候要先确认 SDK 最终发出去的 JSON 是什么,而不是只看业务代码里拼出来的对象。
常见原因判断
1. 请求体结构不符合接口
不少 422 是字段混用导致的。例如某些接口使用 input,某些聊天接口使用 messages。把两套写法混在一起,或者字段层级放错,就容易触发 422。
错误示例:
{
"model": "codex",
"message": "帮我分析这段代码"
}
更合理的写法通常应该是把内容放到接口要求的字段中,例如:
{
"model": "codex",
"input": "帮我分析这段代码"
}
具体字段以你当前使用的接口文档为准,不同网关或 SDK 封装可能会有差异。
2. 参数类型传错
这是项目里最常见的一类问题。比如 temperature 应该是数字,结果从环境变量读出来后变成字符串;stream 应该是布尔值,结果传了 "true"。
{
"model": "codex",
"input": "生成一个排序函数",
"temperature": "0.2",
"stream": "false"
}
建议改成:
{
"model": "codex",
"input": "生成一个排序函数",
"temperature": 0.2,
"stream": false
}
3. 空字符串、空数组或 null
有些参数在业务上看起来“没传”,但序列化以后变成了 null 或空数组。比如前端没有填写提示词,后端仍然发出了:
{
"model": "codex",
"input": ""
}
这种请求很容易被判定为无效参数。修复方式是在调用前做一次基础校验:
if (!prompt || !prompt.trim()) {
throw new Error("prompt 不能为空");
}
4. 模型名或网关配置不匹配
如果你接的是 API 中转服务,还要确认模型名是否和中转侧支持的名称一致。有些平台会对模型名做映射,有些则要求严格传入指定名称。排查这类问题时,我一般会先用最小请求体跑通,再逐步加参数。临时调试或多模型切换时,可以考虑使用 token云桥AI中转站 0029.org 这类中转入口,重点是方便对比不同模型和参数是否被正确转发,不要在业务代码里盲目猜字段。
逐步排查顺序
第一步:打印原始请求和响应
后端不要只打印“调用失败”,最好把状态码、响应体、请求体都记录下来。注意线上日志要脱敏,不要把完整密钥打出来。
console.log("status:", err.status);
console.log("response:", err.response?.data);
console.log("request body:", JSON.stringify(payload, null, 2));
Python 项目可以这样处理:
try:
resp = client.responses.create(**payload)
except Exception as e:
print("error:", repr(e))
print("payload:", json.dumps(payload, ensure_ascii=False, indent=2))
第二步:用 curl 复现最小请求
把 SDK 先放一边,用 curl 发一个最小可用请求。如果最小请求能成功,说明密钥、地址、模型基本没问题,错误大概率在你额外加的参数里。
curl -sS -X POST "$BASE_URL/responses" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "codex",
"input": "写一个 JavaScript 防抖函数"
}' | jq .
如果这里仍然是 422,继续检查 BASE_URL、模型名、接口路径和请求结构。很多项目从聊天接口迁移到 Responses 风格接口时,路径改了,但请求体还沿用旧格式。
第三步:逐个加回参数
不要一次性把所有参数都恢复。推荐按下面顺序加回:
- 先加
temperature、max_output_tokens这类基础参数; - 再加
instructions或系统提示; - 最后再加
tools、结构化输出、流式参数; - 每加一项就执行一次请求,确认是哪一个字段触发 422。
如果使用结构化输出,尤其要检查 JSON Schema。字段名写错、required 中包含不存在的字段、类型写成不支持的值,都可能让接口直接返回 422。
修复示例
下面是一个比较典型的修复前请求,问题包括:input 为空、temperature 是字符串、max_output_tokens 是字符串。
{
"model": "codex",
"input": "",
"temperature": "0.3",
"max_output_tokens": "800"
}
修复后:
{
"model": "codex",
"input": "请检查下面这段 Python 代码的异常处理问题,并给出修改建议。",
"temperature": 0.3,
"max_output_tokens": 800
}
如果这些参数来自环境变量,要显式转换类型:
const payload = {
model: process.env.CODEX_MODEL || "codex",
input: prompt.trim(),
temperature: Number(process.env.CODEX_TEMPERATURE || 0.3),
max_output_tokens: Number(process.env.CODEX_MAX_TOKENS || 800)
};
验证修复是否生效
修完以后不要只看“接口不报错”,还要确认响应内容符合预期。可以用下面的命令观察状态码和响应体:
curl -w "\nHTTP_STATUS=%{http_code}\n" -sS -X POST "$BASE_URL/responses" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @request.json
如果返回 HTTP_STATUS=200,再检查输出字段是否存在、内容是否完整。如果是流式调用,还要确认客户端是否按流式协议读取,否则可能误判为接口异常。
避免再次出现 422
- 调用前做参数校验,至少校验必填字段、类型、取值范围;
- 把请求体构造封装到一个函数里,避免各处手写 JSON;
- 环境变量读取后要转换类型,不要直接传字符串;
- 升级 SDK 后重新跑一遍最小请求,确认字段没有变化;
- 日志记录状态码和错误响应,但密钥、用户输入要做脱敏处理;
- 对中转服务和官方接口分别保留一份可运行的 curl 示例,方便定位是业务参数问题还是网关映射问题。
总结
Codex 返回 422 时,优先按“请求体结构、参数类型、空值、模型名、扩展参数”这个顺序排查。最有效的方法是先用最小 curl 请求跑通,再逐个加回业务参数。不要只盯着 SDK 异常文本,完整请求体和响应体才是定位 422 的关键。
更多推荐


所有评论(0)