openai/codex · error · std::io::Error
remote control requires ChatGPT authentication
Error message
remote control requires ChatGPT authentication
What it means
load_remote_control_auth found no auth at all: AuthManager.auth() returned None, one automatic reload was attempted, and it was still None. Remote-control endpoints (pairing, enrollment, client list/revoke, preference persistence) act as the signed-in ChatGPT user, so the call is rejected up front with PermissionDenied instead of sending an unauthenticated request.
Source
Thrown at codex-rs/app-server-transport/src/transport/remote_control/auth.rs:44
HeaderValue::from_str(&self.account_id).map_err(|err| {
io::Error::new(
ErrorKind::InvalidInput,
format!("invalid remote control account id header: {err}"),
)
})?,
);
Ok(headers)
}
}
pub(super) async fn load_remote_control_auth(
auth_manager: &Arc<AuthManager>,
) -> io::Result<RemoteControlConnectionAuth> {
let mut reloaded = false;
let auth = loop {
let Some(auth) = auth_manager.auth().await else {
if reloaded {
return Err(io::Error::new(
ErrorKind::PermissionDenied,
"remote control requires ChatGPT authentication",
));
}
auth_manager.reload().await;
reloaded = true;
continue;
};
if !auth.uses_codex_backend() {
break auth;
}
if auth.get_account_id().is_none() && !reloaded {
auth_manager.reload().await;
reloaded = true;
continue;
}
break auth;
};View on GitHub (pinned to 339751715c)
Solutions
- Run codex login and choose Sign in with ChatGPT, then retry the remote-control call
- Verify CODEX_HOME resolves to the directory that contains auth.json (ls $CODEX_HOME/auth.json)
- In tests/CI, provision an auth.json fixture or inject a mock AuthManager before invoking remote-control APIs
- Confirm no env/config override redirects the home directory so the reload finds the fresh login
Example fix
// before $ ls "$CODEX_HOME/auth.json" # No such file or directory list_remote_control_clients(url, &auth_manager, params).await // Err: remote control requires ChatGPT authentication // after $ codex login # choose 'Sign in with ChatGPT' list_remote_control_clients(url, &auth_manager, params).await // Ok
Defensive patterns
Strategy: validation
Validate before calling
async fn has_auth(auth_manager: &Arc<AuthManager>) -> bool {
auth_manager.auth().await.is_some()
}
// gate every remote-control call on this; if false, prompt login first Try / catch
Catch io::Error with kind() == PermissionDenied and message 'remote control requires ChatGPT authentication'; route the user to login. Do not loop-retry — the library already performed one reload internally before giving up.
Prevention
- Gate remote-control UI on auth state, not just on feature flags
- Provision fake auth.json or mock AuthManager in CI instead of relying on a real login
- Treat this PermissionDenied as login-required, distinct from a mid-session 401 which triggers unauthorized recovery
When it happens
Trigger: Any remote-control entry point — start_pairing, pairing_status, enroll_pairing_server, refresh_pairing_enrollment, persist_preference, or list/revoke clients via send_client_management_request — when no usable auth is stored (missing or empty CODEX_HOME/auth.json) and the internal single reload does not fix it.
Common situations: Fresh machine or container where codex login was never run; CODEX_HOME pointing at the wrong or an empty directory in CI; auth.json deleted or corrupted after logout; headless servers expected to be pre-provisioned but were not.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- remote control requires ChatGPT authentication; API key auth
- invalid remote control account id header: {err}
- remote control enrollment is waiting for a ChatGPT account i
- {method} rejected legacy params
- {method} failed: {}
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/84c52edb1382679f.
Report an issue: GitHub.