BigPizzaV3/CodexPlusPlus · error · anyhow::Error

Remote Control session recovery is unavailable

Error message

Remote Control session recovery is unavailable

What it means

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.

Source

Thrown at crates/codex-plus-core/src/routes.rs:124

#[async_trait]
pub trait BridgeDataService: Send + Sync {
    async fn delete(&self, session: SessionRef) -> anyhow::Result<DeleteResult>;
    async fn undo(&self, undo_token: String) -> anyhow::Result<DeleteResult>;
    async fn export_markdown(&self, session: SessionRef) -> anyhow::Result<ExportResult>;
    async fn thread_usage_history(&self, session: SessionRef) -> anyhow::Result<Value>;
    async fn find_archived_thread_by_title(
        &self,
        title: String,
    ) -> anyhow::Result<Option<SessionRef>>;
    async fn move_thread_workspace(
        &self,
        session: SessionRef,
        target_cwd: String,
    ) -> anyhow::Result<Value>;
    async fn thread_sort_key(&self, session: SessionRef) -> anyhow::Result<Value>;
    async fn thread_sort_keys(&self, sessions: Vec<SessionRef>) -> anyhow::Result<Value>;
    async fn recover_remote_control_session(&self, _thread_id: String) -> anyhow::Result<Value> {
        anyhow::bail!("Remote Control session recovery is unavailable")
    }
}

pub async fn handle_bridge_request(
    ctx: BridgeContext,
    path: &str,
    payload: Value,
) -> serde_json::Value {
    let started = Instant::now();
    let _ = crate::diagnostic_log::append_diagnostic_log(
        "bridge.request",
        json!({
            "path": path,
            "payload_keys": payload
                .as_object()
                .map(|object| object.keys().cloned().collect::<Vec<_>>())
                .unwrap_or_default()
        }),

View on GitHub (pinned to 1f431ae49b)

Solutions

  1. 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)
  2. Check capability before calling: only invoke '/remote-control-session/recover' on builds known to support it, and hide the UI action otherwise
  3. If embedding, route the BridgeContext through the core data service rather than a Default-based stub
  4. Treat the error message as a capability probe: on this specific message, disable the feature instead of retrying

Example fix

// before
struct MyDataService;
#[async_trait]
impl BridgeDataService for MyDataService { /* required methods only */ }
// after
struct MyDataService;
#[async_trait]
impl BridgeDataService for MyDataService {
    async fn recover_remote_control_session(&self, thread_id: String) -> anyhow::Result<Value> {
        crate::remote_control_recovery::recover(&self.store, &thread_id).await
    }
    /* required methods */
}
Defensive patterns

Strategy: fallback

Try / catch

let value = match ctx.data.recover_remote_control_session(thread_id).await {
    Ok(v) => v,
    Err(e) if e.to_string().contains("recovery is unavailable") => {
        json!({"status": "failed", "supported": false}) // hide the feature, do not retry
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@1f431ae49b (2026-08-16). Data as JSON: /api/errors/3465bc7e8a91292d. Report an issue: GitHub.