{"record":{"id":"3465bc7e8a91292d","repo":"BigPizzaV3/CodexPlusPlus","slug":"remote-control-session-recovery-is-unavailable","errorCode":null,"errorMessage":"Remote Control session recovery is unavailable","messagePattern":"Remote Control session recovery is unavailable","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/routes.rs","lineNumber":124,"sourceCode":"#[async_trait]\npub trait BridgeDataService: Send + Sync {\n    async fn delete(&self, session: SessionRef) -> anyhow::Result<DeleteResult>;\n    async fn undo(&self, undo_token: String) -> anyhow::Result<DeleteResult>;\n    async fn export_markdown(&self, session: SessionRef) -> anyhow::Result<ExportResult>;\n    async fn thread_usage_history(&self, session: SessionRef) -> anyhow::Result<Value>;\n    async fn find_archived_thread_by_title(\n        &self,\n        title: String,\n    ) -> anyhow::Result<Option<SessionRef>>;\n    async fn move_thread_workspace(\n        &self,\n        session: SessionRef,\n        target_cwd: String,\n    ) -> anyhow::Result<Value>;\n    async fn thread_sort_key(&self, session: SessionRef) -> anyhow::Result<Value>;\n    async fn thread_sort_keys(&self, sessions: Vec<SessionRef>) -> anyhow::Result<Value>;\n    async fn recover_remote_control_session(&self, _thread_id: String) -> anyhow::Result<Value> {\n        anyhow::bail!(\"Remote Control session recovery is unavailable\")\n    }\n}\n\npub async fn handle_bridge_request(\n    ctx: BridgeContext,\n    path: &str,\n    payload: Value,\n) -> serde_json::Value {\n    let started = Instant::now();\n    let _ = crate::diagnostic_log::append_diagnostic_log(\n        \"bridge.request\",\n        json!({\n            \"path\": path,\n            \"payload_keys\": payload\n                .as_object()\n                .map(|object| object.keys().cloned().collect::<Vec<_>>())\n                .unwrap_or_default()\n        }),","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/1f431ae49b57b3055e0e6845ba6156c6b4232b4d/crates/codex-plus-core/src/routes.rs#L106-L142","documentation":"recover_remote_control_session has a default implementation on the BridgeDataService trait that always bails with 'Remote Control session recovery is unavailable'. The bridge route '/remote-control-session/recover' dispatches to ctx.data.recover_remote_control_session(thread_id), so the error surfaces when the installed data service does not override the default — i.e. the runtime build has no remote-control backend wired in.","triggerScenarios":"Sending a bridge request to path '/remote-control-session/recover' with payload field 'thread_id' (or 'threadId') while the BridgeDataService implementation behind BridgeContext.data uses the trait default (never overrides recover_remote_control_session). handle_bridge_request converts the bail into a failed response via failed_from_error.","commonSituations":"Embedding codex-plus-core with a minimal/test BridgeDataService that implements only the required trait methods; running a CoreRuntimeService wiring where the remote-control feature is disabled at compile time or behind a feature flag; frontend calling the endpoint on an older build that predates the feature.","solutions":["Provide a real implementation of recover_remote_control_session in your BridgeDataService impl (the production impl already does this — use it instead of a stub)","Check capability before calling: only invoke '/remote-control-session/recover' on builds known to support it, and hide the UI action otherwise","If embedding, route the BridgeContext through the core data service rather than a Default-based stub","Treat the error message as a capability probe: on this specific message, disable the feature instead of retrying"],"exampleFix":"// before\nstruct MyDataService;\n#[async_trait]\nimpl BridgeDataService for MyDataService { /* required methods only */ }\n// after\nstruct MyDataService;\n#[async_trait]\nimpl BridgeDataService for MyDataService {\n    async fn recover_remote_control_session(&self, thread_id: String) -> anyhow::Result<Value> {\n        crate::remote_control_recovery::recover(&self.store, &thread_id).await\n    }\n    /* required methods */\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let value = match ctx.data.recover_remote_control_session(thread_id).await {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"recovery is unavailable\") => {\n        json!({\"status\": \"failed\", \"supported\": false}) // hide the feature, do not retry\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Expose a capability flag (e.g. supported_paths) from the service and have the frontend disable the button","In embedded builds, always route BridgeContext through the production data service instead of a stub impl","Treat this exact message as a permanent condition: never retry it"],"tags":["bridge","remote-control","trait-default","capability-detection","codex-plus-core"],"backgroundTag":"unsupported-operation","analyzedSha":"1f431ae49b57b3055e0e6845ba6156c6b4232b4d","analyzedAt":"2026-08-16T20:54:18.598Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}