mirror of
https://github.com/openai/codex.git
synced 2026-11-13 21:30:47 +00:00
Add structured error kinds for exec-server process starts (#61358)
## What changed Attach a tagged `ProcessStartErrorData` value to JSON-RPC errors for not-found, permission-denied, and other spawn failures, unavailable sandboxes, and sandbox preparation failures. Record the error code and structured error kind for failed `process/start` responses in the `codex.exec_server.response_received` tracing event. GitOrigin-RevId: 556d0068e469ea25e95108262826a77a66b7d83b
This commit is contained in:
@@ -10,6 +10,7 @@ use std::time::Duration;
|
||||
use crate::process_telemetry::ProcessTelemetry;
|
||||
use crate::process_telemetry::ProcessTelemetryEvent;
|
||||
use codex_exec_server_protocol::JSONRPCErrorError;
|
||||
use codex_exec_server_protocol::ProcessStartErrorData;
|
||||
use codex_network_proxy::NetworkPolicyAuditEvent;
|
||||
use codex_network_proxy::NetworkPolicyAuditObserver;
|
||||
use codex_network_proxy::NetworkProtocol;
|
||||
@@ -456,7 +457,17 @@ impl LocalProcess {
|
||||
) {
|
||||
process_map.remove(&process_id);
|
||||
}
|
||||
return Err(internal_error(err.to_string()));
|
||||
let io_error = err
|
||||
.chain()
|
||||
.find_map(|cause| cause.downcast_ref::<std::io::Error>());
|
||||
let kind = match io_error.map(std::io::Error::kind) {
|
||||
Some(std::io::ErrorKind::NotFound) => ProcessStartErrorData::SpawnNotFound,
|
||||
Some(std::io::ErrorKind::PermissionDenied) => {
|
||||
ProcessStartErrorData::SpawnPermissionDenied
|
||||
}
|
||||
_ => ProcessStartErrorData::SpawnFailed,
|
||||
};
|
||||
return Err(kind.attach_to(internal_error(err.to_string())));
|
||||
}
|
||||
};
|
||||
let metrics = self.inner.telemetry.process_started(&process_id);
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::process_telemetry::ProcessTelemetry;
|
||||
use codex_exec_server_protocol::JSONRPCErrorError;
|
||||
use codex_exec_server_protocol::ProcessStartErrorData;
|
||||
use codex_file_system::WindowsSandboxSelection;
|
||||
use codex_network_proxy::CHILD_ONLY_CA_ENV_KEYS;
|
||||
use codex_network_proxy::CUSTOM_CA_ENV_KEYS;
|
||||
@@ -123,9 +124,11 @@ pub(crate) async fn prepare_exec_request_with_telemetry(
|
||||
));
|
||||
}
|
||||
if !codex_sandboxing::windows_mxc_available() {
|
||||
return Err(invalid_params(
|
||||
"native MXC is unavailable on this executor".to_owned(),
|
||||
));
|
||||
return Err(
|
||||
ProcessStartErrorData::SandboxUnavailable.attach_to(invalid_params(
|
||||
"native MXC is unavailable on this executor".to_owned(),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
let (env, managed_network, network_proxy_handle, network_proxy_restricting_sid) =
|
||||
@@ -150,8 +153,11 @@ pub(crate) async fn prepare_exec_request_with_telemetry(
|
||||
windows_sandbox: None,
|
||||
});
|
||||
};
|
||||
let runtime_paths = runtime_paths
|
||||
.ok_or_else(|| invalid_params("sandbox runtime paths are not configured".to_string()))?;
|
||||
let runtime_paths = runtime_paths.ok_or_else(|| {
|
||||
ProcessStartErrorData::SandboxUnavailable.attach_to(invalid_params(
|
||||
"sandbox runtime paths are not configured".to_string(),
|
||||
))
|
||||
})?;
|
||||
let windows_sandbox_proxy_settings_mode = sandbox_context
|
||||
.windows_sandbox_proxy_settings_mode
|
||||
.unwrap_or_default();
|
||||
@@ -247,9 +253,9 @@ pub(crate) async fn prepare_exec_request_with_telemetry(
|
||||
})
|
||||
.map_err(|err| match err {
|
||||
codex_sandboxing::SandboxTransformError::SandboxUnavailable => {
|
||||
invalid_params(err.to_string())
|
||||
ProcessStartErrorData::SandboxUnavailable.attach_to(invalid_params(err.to_string()))
|
||||
}
|
||||
err => invalid_params(format!("failed to prepare process sandbox: {err}")),
|
||||
err => sandbox_preparation_error(err),
|
||||
})?
|
||||
.into_command_request();
|
||||
request.sandbox_override = sandbox_context.sandbox_override;
|
||||
@@ -271,7 +277,7 @@ pub(crate) async fn prepare_exec_request_with_telemetry(
|
||||
windows_sandbox_level,
|
||||
&request.env,
|
||||
)
|
||||
.map_err(|err| invalid_params(format!("failed to prepare process sandbox: {err}")))?;
|
||||
.map_err(sandbox_preparation_error)?;
|
||||
Some(PreparedWindowsSandboxRequest {
|
||||
permission_profile: permissions,
|
||||
workspace_roots: native_workspace_roots,
|
||||
@@ -433,6 +439,12 @@ async fn prepare_managed_network(
|
||||
))
|
||||
}
|
||||
|
||||
fn sandbox_preparation_error(err: impl std::fmt::Display) -> JSONRPCErrorError {
|
||||
ProcessStartErrorData::SandboxPreparation.attach_to(invalid_params(format!(
|
||||
"failed to prepare process sandbox: {err}"
|
||||
)))
|
||||
}
|
||||
|
||||
fn native_path(path: &PathUri, label: &str) -> Result<AbsolutePathBuf, JSONRPCErrorError> {
|
||||
path.to_abs_path().map_err(|err| {
|
||||
invalid_params(format!(
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
use codex_exec_server_protocol::ProcessStartErrorData;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::protocol::EXEC_METHOD;
|
||||
use crate::rpc::RpcCallError;
|
||||
|
||||
pub(crate) struct RpcCompletion {
|
||||
@@ -20,9 +23,17 @@ impl RpcCompletion {
|
||||
}
|
||||
|
||||
pub(crate) fn record_receipt(&self, method: &str) {
|
||||
let outcome = match &self.result {
|
||||
Ok(_) => "success",
|
||||
Err(RpcCallError::Server(_)) => "error",
|
||||
let (outcome, start_error_code, start_error_kind) = match &self.result {
|
||||
Ok(_) => ("success", None, None),
|
||||
Err(RpcCallError::Server(error)) if method == EXEC_METHOD => (
|
||||
"error",
|
||||
Some(error.code),
|
||||
error
|
||||
.data
|
||||
.as_ref()
|
||||
.and_then(|data| ProcessStartErrorData::deserialize(data).ok()),
|
||||
),
|
||||
Err(RpcCallError::Server(_)) => ("error", None, None),
|
||||
Err(
|
||||
RpcCallError::Closed
|
||||
| RpcCallError::Json(_)
|
||||
@@ -37,6 +48,8 @@ impl RpcCompletion {
|
||||
event.name = "codex.exec_server.response_received",
|
||||
rpc.method = method,
|
||||
outcome,
|
||||
process.start_error_code = start_error_code,
|
||||
process.start_error_kind = start_error_kind.as_ref().map(tracing::field::debug),
|
||||
reader_to_caller_ns = i64::try_from(self.completed_at.elapsed().as_nanos())
|
||||
.unwrap_or(i64::MAX),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user