openai/codex · error · std::io::Error
agents.max_concurrent_threads_per_session must be at least 1
Error message
agents.max_concurrent_threads_per_session must be at least 1
What it means
The top-level `[agents]` table has its own concurrency limit. Only an explicit zero triggers the error (the check is agent_max_threads == Some(0)); an absent key passes and the default applies, so this always means someone wrote max_concurrent_threads_per_session = 0.
Source
Thrown at codex-rs/core/src/config/mod.rs:3756
}
if multi_agent_v2.default_wait_timeout_ms > multi_agent_v2.max_wait_timeout_ms {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"features.multi_agent_v2.default_wait_timeout_ms must be at most features.multi_agent_v2.max_wait_timeout_ms",
));
}
validate_multi_agent_v2_tool_namespace(multi_agent_v2.tool_namespace.as_deref())?;
let agents_enabled = cfg
.agents
.as_ref()
.and_then(|agents| agents.enabled)
.unwrap_or(true);
let agent_max_threads = cfg
.agents
.as_ref()
.and_then(|agents| agents.max_concurrent_threads_per_session);
if agent_max_threads == Some(0) {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"agents.max_concurrent_threads_per_session must be at least 1",
));
}
let agent_max_depth = cfg
.agents
.as_ref()
.and_then(|agents| agents.max_depth)
.unwrap_or(DEFAULT_AGENT_MAX_DEPTH);
let agent_default_subagent_model = cfg
.agents
.as_ref()
.and_then(|agents| agents.default_subagent_model.clone());
let agent_default_subagent_reasoning_effort = cfg
.agents
.as_ref()
.and_then(|agents| agents.default_subagent_reasoning_effort.clone());
let agent_interrupt_message_enabled = cfgView on GitHub (pinned to 339751715c)
Solutions
- Set `[agents]` `max_concurrent_threads_per_session` to 1 or higher.
- Or remove the key to use the default.
- To disable agents entirely, set `enabled = false` under `[agents]`.
Example fix
# before [agents] max_concurrent_threads_per_session = 0 # after [agents] max_concurrent_threads_per_session = 4 # or disable agents instead # [agents] # enabled = false
Defensive patterns
Strategy: validation
Validate before calling
import tomllib
agents = tomllib.load(open("config.toml", "rb")).get("agents", {})
limit = agents.get("max_concurrent_threads_per_session")
assert limit is None or limit >= 1, "agents.max_concurrent_threads_per_session must be >= 1" Try / catch
match config_result {
Err(ref e) if e.kind() == std::io::ErrorKind::InvalidInput
&& e.to_string().contains("agents.max_concurrent_threads_per_session") => {
// clamp to 1 or drop the key, then retry
}
other => other,
} Prevention
- Zero is not a valid concurrency limit in [agents] or [features.multi_agent_v2]
- Use enabled = false to turn agents off
- Validate both concurrency knobs in config pre-flight checks
When it happens
Trigger: `[agents]` with `max_concurrent_threads_per_session = 0` in any loaded layer, with agents enabled (or enabled unset, which defaults to true).
Common situations: Same mistake as the multi_agent_v2 twin of this knob: trying to disable subagents by zeroing the limit; stale tuned configs; managed layers zeroing the limit.
Related errors
- Invalid MCP server name '{server_name}': must match pattern
- config defines `[permissions]` profiles but does not set `de
- features.multi_agent_v2.max_concurrent_threads_per_session m
- Environment variable {env_var} for MCP server '{server_name}
- executor-owned MCP server `{server_name}` cannot use hosted
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/0c1d7c6d9c653fb0.
Report an issue: GitHub.