openai/codex · error · io::Error

remote control client revoke requires environmentId

Error message

remote control client revoke requires environmentId

What it means

revoke_remote_control_client first validates that RemoteControlClientsRevokeParams.environment_id is non-empty, failing fast with InvalidInput before constructing the DELETE URL. Revocation targets one client inside one environment, so the environment scope is mandatory.

Source

Thrown at codex-rs/app-server-transport/src/transport/remote_control/clients.rs:130

        },
    )?;
    Ok(RemoteControlClientsListResponse {
        data: response
            .items
            .into_iter()
            .map(RemoteControlClient::try_from)
            .collect::<io::Result<_>>()?,
        next_cursor: response.cursor,
    })
}

pub(super) async fn revoke_remote_control_client(
    remote_control_url: &str,
    auth_manager: &Arc<AuthManager>,
    params: RemoteControlClientsRevokeParams,
) -> io::Result<RemoteControlClientsRevokeResponse> {
    if params.environment_id.is_empty() {
        return Err(io::Error::new(
            ErrorKind::InvalidInput,
            "remote control client revoke requires environmentId",
        ));
    }
    if params.client_id.is_empty() {
        return Err(io::Error::new(
            ErrorKind::InvalidInput,
            "remote control client revoke requires clientId",
        ));
    }
    let mut url = environment_clients_url(remote_control_url, &params.environment_id)?;
    url.path_segments_mut()
        .map_err(|()| {
            io::Error::new(
                ErrorKind::InvalidInput,
                "remote control URL cannot be a base",
            )
        })?

View on GitHub (pinned to 339751715c)

Solutions

  1. Pass the same environmentId that produced the client list the selection came from
  2. Populate both environmentId and clientId from the selected client's owning context before invoking revoke
  3. Validate the request payload client-side before sending

Example fix

// before
let params = RemoteControlClientsRevokeParams {
    environment_id: String::new(),
    client_id: client.client_id.clone(),
};
revoke_remote_control_client(url, &auth_manager, params).await
// Err: remote control client revoke requires environmentId

// after
let params = RemoteControlClientsRevokeParams {
    environment_id: environment_id.clone(),
    client_id: client.client_id.clone(),
};
revoke_remote_control_client(url, &auth_manager, params).await  // Ok
Defensive patterns

Strategy: validation

Validate before calling

fn can_revoke(p: &RemoteControlClientsRevokeParams) -> bool {
    !p.environment_id.is_empty() && !p.client_id.is_empty()
}

Type guard

function isRevokeReady(p: RemoteControlClientsRevokeParams): p is RemoteControlClientsRevokeParams & { environmentId: string; clientId: string } {
  return typeof p.environmentId === 'string' && p.environmentId.length > 0
      && typeof p.clientId === 'string' && p.clientId.length > 0;
}

Prevention

When it happens

Trigger: Calling the client revoke RPC with a blank environmentId — reusing params whose field was never set, or a UI revoking a client after the active environment context was cleared.

Common situations: Client selected from a stale list after environment context reset; JSON payload built with only clientId; multi-environment dashboards losing track of which environment the client belongs to.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/b98fc544c5466564. Report an issue: GitHub.