OmniRoute Version
3.7.8
Installation Method
npm (global)
Operating System
Linux
OS Version
Debian 12
Node.js Version
22.12.0
Provider(s) Involved
codex
Model(s) Involved
cx/gpt-5.4
Client Tool
codex
Description
OmniRoute upstream fix guide: Codex Responses tools[0].name error
Issue
Codex /v1/responses requests can fail with:
[400]: Missing required parameter: 'tools[0].name'.
Observed route:
/v1/responses | cx/gpt-5.4 | 108 msgs | 7 tools | effort=medium
cx/gpt-5.4 -> codex/gpt-5.4
provider=codex
model=gpt-5.4
sourceFormat=openai-responses
targetFormat=openai-responses
status=400
Concrete failed call metadata from local deployment:
id=a839b502-7e78-4e39-b68d-4cbc85614e0e
timestamp=2026-05-03T12:42:38.589Z
path=/v1/responses
provider=codex
model=gpt-5.4
requestedModel=codex/gpt-5.4
error=[400]: Missing required parameter: 'tools[0].name'.
Sensitive data note
The raw artifact is not included here because it may contain user/project content.
Only redacted structural information is included.
Root cause
The request sent to Codex Responses API contained a mixed tools array.
Some tools were already in Responses API format:
{
"type": "function",
"name": "...",
"description": "...",
"parameters": { ... },
"strict": false
}
But some tools remained in Chat Completions legacy format:
{
"type": "function",
"function": {
"name": "...",
"description": "...",
"parameters": { ... }
}
}
Codex /v1/responses requires function tools to have top-level name.
Therefore a legacy-format tool at tools[0] causes:
Missing required parameter: 'tools[0].name'.
Redacted tool shape from failing payload
Total tools: 7
Tool 0:
- keys: function, type
- type: function
- has top-level name: false
- has function.name: true
- has top-level parameters: false
- has function.parameters: true
- Result: invalid for Codex Responses API
Tool 1:
- keys: description, name, parameters, strict, type
- has top-level name: true
- Result: valid Responses-style tool
Tool 2:
- keys: description, name, parameters, strict, type
- has top-level name: true
- Result: valid Responses-style tool
Tool 3:
- keys: description, name, parameters, strict, type
- has top-level name: true
- Result: valid Responses-style tool
Tool 4:
- keys: description, name, parameters, strict, type
- has top-level name: true
- Result: valid Responses-style tool
Tool 5:
- keys: function, type
- type: function
- has top-level name: false
- has function.name: true
- Result: invalid for Codex Responses API
Tool 6:
- keys: description, name, parameters, strict, type
- has top-level name: true
- Result: valid Responses-style tool
Relevant code
File:
open-sse/executors/codex.ts
Function:
normalizeCodexTools(body)
Current behavior, simplified:
- If tool.type === "function", it attempts to find a name from either:
- tool.name
- tool.function.name
- If a name exists, the tool is kept.
- But if the input tool was legacy Chat format, it is not rewritten to Responses format.
The problematic behavior is that this legacy Chat-format tool is accepted:
{
"type": "function",
"function": {
"name": "some_tool",
"description": "...",
"parameters": { "type": "object", "properties": {} }
}
}
But it is still sent upstream in that shape, where Codex Responses requires:
{
"type": "function",
"name": "some_tool",
"description": "...",
"parameters": { "type": "object", "properties": {} }
}
Recommended fix
In normalizeCodexTools(body), normalize all function tools into Codex Responses format before sending upstream.
For function tools:
- Accept name from top-level
tool.name or legacy tool.function.name.
- Accept description from top-level
tool.description or legacy tool.function.description.
- Accept parameters from top-level
tool.parameters or legacy tool.function.parameters.
- Rewrite the object to:
{
type: "function",
name,
description,
parameters
}
- Remove the legacy
function wrapper.
Suggested patch logic
This is the local patch that fixed the issue in production:
const rawName =
typeof tool.name === "string"
? tool.name
: tool.function &&
typeof tool.function === "object" &&
!Array.isArray(tool.function) &&
typeof (tool.function as Record<string, unknown>).name === "string"
? ((tool.function as Record<string, unknown>).name as string)
: "";
const name = rawName.trim();
if (!name) {
return false;
}
const functionObject =
tool.function &&
typeof tool.function === "object" &&
!Array.isArray(tool.function)
? (tool.function as Record<string, unknown>)
: null;
const description =
typeof tool.description === "string"
? tool.description
: typeof functionObject?.description === "string"
? functionObject.description
: "";
const parameters =
tool.parameters &&
typeof tool.parameters === "object" &&
!Array.isArray(tool.parameters)
? tool.parameters
: functionObject?.parameters &&
typeof functionObject.parameters === "object" &&
!Array.isArray(functionObject.parameters)
? functionObject.parameters
: { type: "object", properties: {} };
// Codex Responses requires function tools in Responses format:
// { type: "function", name, description, parameters }.
// Some clients/translators can leave Chat Completions tools shaped as
// { type: "function", function: { name, description, parameters } },
// which upstream rejects with Missing required parameter: tools[0].name.
for (const key of Object.keys(tool)) {
delete tool[key];
}
tool.type = "function";
tool.name = name;
if (description) tool.description = description;
tool.parameters = parameters;
validToolNames.add(name);
return true;
Important behavior
This fix should preserve already-valid Responses-format tools.
Input:
{
"type": "function",
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
Output should stay:
{
"type": "function",
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
Legacy input:
{
"type": "function",
"function": {
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
}
Output should become:
{
"type": "function",
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
Suggested tests
Add unit tests for normalizeCodexTools or the Codex request preparation path.
Test 1: preserves Responses-format tool
Input:
{
"tools": [
{
"type": "function",
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
Expected:
{
"tools": [
{
"type": "function",
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
Test 2: converts Chat Completions legacy tool to Responses format
Input:
{
"tools": [
{
"type": "function",
"function": {
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
}
]
}
Expected:
{
"tools": [
{
"type": "function",
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
Test 3: filters invalid function tools without any name
Input:
{
"tools": [
{
"type": "function",
"function": {
"parameters": { "type": "object", "properties": {} }
}
}
]
}
Expected:
{
"tools": []
}
Test 4: mixed tools array
Input should include:
- one Responses-format function tool
- one Chat-format function tool
- one invalid function tool without name
Expected:
- first tool preserved
- second tool converted
- invalid tool removed
Deployment verification from local fix
After applying the local patch, rebuilding, restoring env, and restarting, verification showed:
tools[0].name count since new process: 0
Missing required parameter count since new process: 0
gpt-5.4 400 count since new process: 0
gpt-5.4 200 count since new process: 15
Service health after patch:
MainPID=193524
NRestarts=0
ExecMainStatus=0
Description=OmniRoute 3.7.8 + kiro-opus45-fix
ActiveState=active
SubState=running
cwd=/opt/omniroute/releases/3.7.8
HTTP=307
DB=ok
env_match=yes
build_id=UNg0gR4BPH45cDSd1n0sW
Conclusion
This is a tool normalization bug in the Codex Responses path.
The fix is to convert legacy Chat Completions function tools into Responses API function tools before sending to Codex /v1/responses.
Filtering/validating name is not enough. The object shape must be rewritten so every function tool has top-level name and parameters.
Steps to Reproduce
Missing required parameter: 'tools[0].name
Expected Behavior
Missing required parameter: 'tools[0].name
Actual Behavior
Missing required parameter: 'tools[0].name
Test Impact
Needs a new unit test
Error Logs / Output
Screenshots
No response
Additional Context
No response
Validation Plan
No response
OmniRoute Version
3.7.8
Installation Method
npm (global)
Operating System
Linux
OS Version
Debian 12
Node.js Version
22.12.0
Provider(s) Involved
codex
Model(s) Involved
cx/gpt-5.4
Client Tool
codex
Description
OmniRoute upstream fix guide: Codex Responses tools[0].name error
Issue
Codex /v1/responses requests can fail with:
[400]: Missing required parameter: 'tools[0].name'.
Observed route:
/v1/responses | cx/gpt-5.4 | 108 msgs | 7 tools | effort=medium
cx/gpt-5.4 -> codex/gpt-5.4
provider=codex
model=gpt-5.4
sourceFormat=openai-responses
targetFormat=openai-responses
status=400
Concrete failed call metadata from local deployment:
id=a839b502-7e78-4e39-b68d-4cbc85614e0e
timestamp=2026-05-03T12:42:38.589Z
path=/v1/responses
provider=codex
model=gpt-5.4
requestedModel=codex/gpt-5.4
error=[400]: Missing required parameter: 'tools[0].name'.
Sensitive data note
The raw artifact is not included here because it may contain user/project content.
Only redacted structural information is included.
Root cause
The request sent to Codex Responses API contained a mixed tools array.
Some tools were already in Responses API format:
{
"type": "function",
"name": "...",
"description": "...",
"parameters": { ... },
"strict": false
}
But some tools remained in Chat Completions legacy format:
{
"type": "function",
"function": {
"name": "...",
"description": "...",
"parameters": { ... }
}
}
Codex /v1/responses requires function tools to have top-level
name.Therefore a legacy-format tool at tools[0] causes:
Missing required parameter: 'tools[0].name'.
Redacted tool shape from failing payload
Total tools: 7
Tool 0:
Tool 1:
Tool 2:
Tool 3:
Tool 4:
Tool 5:
Tool 6:
Relevant code
File:
open-sse/executors/codex.ts
Function:
normalizeCodexTools(body)
Current behavior, simplified:
The problematic behavior is that this legacy Chat-format tool is accepted:
{
"type": "function",
"function": {
"name": "some_tool",
"description": "...",
"parameters": { "type": "object", "properties": {} }
}
}
But it is still sent upstream in that shape, where Codex Responses requires:
{
"type": "function",
"name": "some_tool",
"description": "...",
"parameters": { "type": "object", "properties": {} }
}
Recommended fix
In normalizeCodexTools(body), normalize all function tools into Codex Responses format before sending upstream.
For function tools:
tool.nameor legacytool.function.name.tool.descriptionor legacytool.function.description.tool.parametersor legacytool.function.parameters.{
type: "function",
name,
description,
parameters
}
functionwrapper.Suggested patch logic
This is the local patch that fixed the issue in production:
Important behavior
This fix should preserve already-valid Responses-format tools.
Input:
{
"type": "function",
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
Output should stay:
{
"type": "function",
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
Legacy input:
{
"type": "function",
"function": {
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
}
Output should become:
{
"type": "function",
"name": "a",
"description": "desc",
"parameters": { "type": "object", "properties": {} }
}
Suggested tests
Add unit tests for normalizeCodexTools or the Codex request preparation path.
Test 1: preserves Responses-format tool
Input:
{
"tools": [
{
"type": "function",
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
Expected:
{
"tools": [
{
"type": "function",
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
Test 2: converts Chat Completions legacy tool to Responses format
Input:
{
"tools": [
{
"type": "function",
"function": {
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
}
]
}
Expected:
{
"tools": [
{
"type": "function",
"name": "search",
"description": "Search docs",
"parameters": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
Test 3: filters invalid function tools without any name
Input:
{
"tools": [
{
"type": "function",
"function": {
"parameters": { "type": "object", "properties": {} }
}
}
]
}
Expected:
{
"tools": []
}
Test 4: mixed tools array
Input should include:
Expected:
Deployment verification from local fix
After applying the local patch, rebuilding, restoring env, and restarting, verification showed:
tools[0].name count since new process: 0
Missing required parameter count since new process: 0
gpt-5.4 400 count since new process: 0
gpt-5.4 200 count since new process: 15
Service health after patch:
MainPID=193524
NRestarts=0
ExecMainStatus=0
Description=OmniRoute 3.7.8 + kiro-opus45-fix
ActiveState=active
SubState=running
cwd=/opt/omniroute/releases/3.7.8
HTTP=307
DB=ok
env_match=yes
build_id=UNg0gR4BPH45cDSd1n0sW
Conclusion
This is a tool normalization bug in the Codex Responses path.
The fix is to convert legacy Chat Completions function tools into Responses API function tools before sending to Codex /v1/responses.
Filtering/validating name is not enough. The object shape must be rewritten so every function tool has top-level
nameandparameters.Steps to Reproduce
Missing required parameter: 'tools[0].name
Expected Behavior
Missing required parameter: 'tools[0].name
Actual Behavior
Missing required parameter: 'tools[0].name
Test Impact
Needs a new unit test
Error Logs / Output
Screenshots
No response
Additional Context
No response
Validation Plan
No response