From b8b54e10f9cfe5712979580c91085f22df3dfbcd Mon Sep 17 00:00:00 2001 From: David Wiesen Date: Wed, 17 Jun 2026 12:53:20 -0700 Subject: [PATCH] Preserve config writes for unrelated load errors --- .../app-server/src/config_manager_service.rs | 24 ++++++++------ .../src/config_manager_service_tests.rs | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/codex-rs/app-server/src/config_manager_service.rs b/codex-rs/app-server/src/config_manager_service.rs index 1e3e333fbf..db8f24e35d 100644 --- a/codex-rs/app-server/src/config_manager_service.rs +++ b/codex-rs/app-server/src/config_manager_service.rs @@ -320,15 +320,21 @@ impl ConfigManager { format!("Invalid configuration: {err}"), ) })?; - codex_core::config::validate_materialized_config_from_layer_stack( - self.codex_home().to_path_buf(), - updated_layers.clone(), - codex_core::config::ConfigOverrides::default(), - ) - .await - .map_err(|err| { - ConfigManagerError::write(ConfigWriteErrorCode::ConfigValidationError, err.to_string()) - })?; + let materialized_config_validation = + codex_core::config::validate_materialized_config_from_layer_stack( + self.codex_home().to_path_buf(), + updated_layers.clone(), + codex_core::config::ConfigOverrides::default(), + ) + .await; + if let Err(err) = materialized_config_validation + && codex_core::config::is_windows_sandbox_network_proxy_incompatible_error(&err) + { + return Err(ConfigManagerError::write( + ConfigWriteErrorCode::ConfigValidationError, + err.to_string(), + )); + } if !config_edits.is_empty() { ConfigEditsBuilder::for_config_path(provided_path.as_path()) diff --git a/codex-rs/app-server/src/config_manager_service_tests.rs b/codex-rs/app-server/src/config_manager_service_tests.rs index 7b1be97939..1a65653df6 100644 --- a/codex-rs/app-server/src/config_manager_service_tests.rs +++ b/codex-rs/app-server/src/config_manager_service_tests.rs @@ -742,6 +742,37 @@ personality = true ); } +#[tokio::test] +async fn write_value_ignores_unrelated_materialized_config_errors() -> Result<()> { + let tmp = tempdir().expect("tempdir"); + let config_path = tmp.path().join(CONFIG_TOML_FILE); + std::fs::write(&config_path, "model_provider = \"missing\"\n")?; + + let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf()); + service + .write_value(ConfigValueWriteParams { + file_path: Some(config_path.display().to_string()), + key_path: "features.personality".to_string(), + value: serde_json::json!(true), + merge_strategy: MergeStrategy::Replace, + expected_version: None, + }) + .await?; + + let actual: TomlValue = toml::from_str(&std::fs::read_to_string(&config_path)?)?; + let expected: TomlValue = toml::from_str( + r#" +model_provider = "missing" + +[features] +personality = true +"#, + )?; + assert_eq!(actual, expected); + + Ok(()) +} + #[cfg(target_os = "windows")] #[tokio::test] async fn batch_write_rejects_unelevated_windows_sandbox_with_network_proxy() -> Result<()> {