openai/codex · error · anyhow::Error
app-server user-agent omitted version
Error message
app-server user-agent omitted version
What it means
The second half of the version parse: after splitting on '/', the remainder must start with a non-empty whitespace-delimited token (the version). A user_agent like 'codex_app_server/' or one whose post-slash text is only whitespace fails here. Like [47] it fires inside probe() from the InitializeResponse, signaling a malformed or foreign agent string rather than a transport problem.
Source
Thrown at codex-rs/app-server-daemon/src/client.rs:156
.await
.ok_or_else(|| anyhow!("app-server closed the control socket"))??;
let Message::Text(payload) = frame else {
continue;
};
return serde_json::from_str::<JSONRPCMessage>(&payload)
.context("failed to parse app-server JSON-RPC message");
}
}
fn parse_version_from_user_agent(user_agent: &str) -> Result<String> {
let (_originator, rest) = user_agent
.split_once('/')
.ok_or_else(|| anyhow!("app-server user-agent omitted version separator"))?;
let version = rest
.split_whitespace()
.next()
.filter(|version| !version.is_empty())
.ok_or_else(|| anyhow!("app-server user-agent omitted version"))?;
Ok(version.to_string())
}
#[cfg(all(test, unix))]
mod tests {
use pretty_assertions::assert_eq;
use super::parse_version_from_user_agent;
#[test]
fn parses_version_from_codex_user_agent() {
assert_eq!(
parse_version_from_user_agent(
"codex_app_server_daemon/1.2.3 (Linux 6.8.0; x86_64) codex_cli_rs/1.2.3",
)
.expect("version"),
"1.2.3"
);View on GitHub (pinned to 339751715c)
Solutions
- Fix the server's user_agent to 'name/x.y.z …' with a real version token first.
- Restart the daemon to respawn a managed server with a known-good agent string.
- Verify daemon and app-server come from the same codex release.
- If the version is genuinely unavailable, decide explicitly how to degrade instead of letting probe abort the lifecycle.
Example fix
// before
user_agent: format!("{}/", name),
// after
user_agent: format!("{}/{}", name, env!("CARGO_PKG_VERSION")), Defensive patterns
Strategy: fallback
Type guard
fn user_agent_has_version(user_agent: &str) -> bool {
user_agent
.split_once('/')
.and_then(|(_, rest)| rest.split_whitespace().next())
.is_some_and(|version| !version.is_empty())
} Try / catch
let info = match probe(&path).await {
Ok(info) => info,
Err(err) if err.to_string().contains("user-agent omitted version") => {
ProbeInfo { app_server_version: "unknown".into() } // degrade, then restart the managed server
}
Err(err) => return Err(err),
}; Prevention
- Always compose user_agent as 'name/<real version>', never a bare separator.
- Feed the version from the build system (env!("CARGO_PKG_VERSION")) so it can't be empty.
- Test custom servers against probe() in CI to catch agent-string regressions.
When it happens
Trigger: probe() against a server whose user_agent ends at the separator ('name/') or continues with only whitespace or parenthetical junk before any version token; custom builds composing the agent from parts and emitting an empty version.
Common situations: Hand-built app-server releases that template the version in separately and ship an empty token; forks renaming the version field; test stubs returning placeholder agent strings.
Related errors
- app-server user-agent omitted version separator
- pid-managed app-server shutdown is unsupported on this platf
- pid-managed updater shutdown is unsupported on this platform
- failed to read start time for pid-managed app server {pid}
- pid-managed app server {pid} has no recorded start time
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/a3417c001c8b65d2.
Report an issue: GitHub.