{"record":{"id":"d5655d96519aebce","repo":"openai/codex","slug":"method-rejected-legacy-params","errorCode":null,"errorMessage":"{method} rejected legacy params","messagePattern":"(.+?) rejected legacy params","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/app-server-daemon/src/remote_control_client.rs","lineNumber":185,"sourceCode":"        Some(params),\n    )\n    .await?;\n    match read_remote_control_response(websocket, &REMOTE_CONTROL_REQUEST_ID, method).await? {\n        RemoteControlRpcResponse::Success(response) => Ok(response),\n        RemoteControlRpcResponse::InvalidParams => {\n            send_remote_control_request(\n                websocket,\n                REMOTE_CONTROL_REQUEST_ID.clone(),\n                method,\n                /*params*/ None,\n            )\n            .await?;\n            match read_remote_control_response(websocket, &REMOTE_CONTROL_REQUEST_ID, method)\n                .await?\n            {\n                RemoteControlRpcResponse::Success(response) => Ok(response),\n                RemoteControlRpcResponse::InvalidParams => {\n                    Err(anyhow!(\"{method} rejected legacy params\"))\n                }\n            }\n        }\n    }\n}\n\nasync fn connect_with_retry(\n    socket_path: &Path,\n    connect_timeout: Duration,\n    connect_retry_delay: Duration,\n) -> Result<WebSocketStream<codex_uds::UnixStream>> {\n    let deadline = Instant::now() + connect_timeout;\n    loop {\n        match client::connect(socket_path).await {\n            Ok(websocket) => return Ok(websocket),\n            Err(_) if Instant::now() < deadline => {\n                sleep(connect_retry_delay).await;\n            }","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/app-server-daemon/src/remote_control_client.rs#L167-L203","documentation":"The app-server-daemon remote-control client calls remoteControl/enable or remoteControl/disable twice: first with a params payload such as {\"ephemeral\":true}, then, if the server answers JSON-RPC -32602, once more with params omitted for older servers (request_remote_control_with_legacy_fallback). This error means the second, legacy-shaped attempt was also rejected with Invalid params, so the connected app-server accepts neither parameter shape and the RPC cannot proceed.","triggerScenarios":"Invoking disable_remote_control or enable_remote_control_with_timeout (and its wrappers enable_remote_control / enable_remote_control_with_connect_retry) against an app-server whose remoteControl handler returns -32602 for both the parametrized request and the param-less retry: a build with a different remoteControl params schema, a much older or newer codex binary than the daemon, or a test double that unconditionally replies InvalidParams.","commonSituations":"Version skew between the codex CLI and the app-server it spawns (npm global vs ~/.codex/bin mixed installs); partial upgrades where one binary updated and the other did not; integration-test mock servers that answer -32602 without implementing the retry-then-succeed fallback contract.","solutions":["Align versions: reinstall or update codex so the daemon and the app-server binary come from the same release, then retry; mismatched param schemas between the two are the dominant cause.","Identify the serving binary: read the userAgent in the initialize response (for example codex_app_server/1.2.3) and compare it with the daemon version.","If you control the server or a test mock, implement the fallback contract: answer -32602 to the {\"ephemeral\":true} request and a valid response to the follow-up request with params null, as the tests in remote_control_client.rs do.","If versions match and it persists, capture the websocket frames to log the server's actual InvalidParams message and report it against the app-server remoteControl handler."],"exampleFix":"// before (mock server): always answers -32602\nif method == \"remoteControl/disable\" {\n    reply_error(id, -32602, \"Invalid params\"); // daemon fails: rejected legacy params\n}\n\n// after (mock server): reject params once, then answer the param-less retry\nif method == \"remoteControl/disable\" && req.params.is_some() {\n    reply_error(id, -32602, \"Invalid params\");\n} else if method == \"remoteControl/disable\" {\n    reply_result(id, disable_response()); // legacy shape accepted\n}","handlingStrategy":"try-catch","validationCode":"// After client::initialize, compare the server's reported version with the\n// daemon's before issuing remoteControl RPCs (sketch):\nlet ua = initialize_result[\"userAgent\"].as_str().unwrap_or_default();\nif !same_release(ua, daemon_version()) {\n    return Err(anyhow!(\"app-server {ua} differs from daemon {}; align installs\", daemon_version()));\n}","typeGuard":null,"tryCatchPattern":"match enable_remote_control(&socket_path).await {\n    Ok(status) => { /* proceed */ }\n    Err(err) if err.to_string().contains(\"rejected legacy params\") => {\n        // Both param shapes refused: treat as version skew and surface an\n        // actionable error instead of retrying the same request.\n        return Err(err.context(\"app-server rejected every remoteControl param shape; daemon and app-server versions likely differ\"));\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Keep a single codex installation on PATH and under ~/.codex so daemon and app-server binaries never diverge.","In test doubles, implement the full fallback contract: reject the parametrized request, then answer the param-less retry.","Read the initialize response userAgent before issuing remoteControl RPCs to unknown server builds.","Drive remoteControl param shapes from codex-app-server-protocol types instead of hand-rolled JSON across versions."],"tags":["remote-control","json-rpc","invalid-params","version-mismatch","app-server-daemon"],"backgroundTag":"json-rpc-invalid-params","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}