codex - ✅(Solved) Fix app-server config/value/write returns configPathNotFound when clearing an unset nested config value [2 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#20145Fetched 2026-04-30 06:33:11
View on GitHub
Comments
1
Participants
2
Timeline
5
Reactions
0
Timeline (top)
cross-referenced ×2labeled ×2commented ×1

Error Message

I reproduced this locally with a focused regression test against ConfigManager::write_value: clearing features.personality from an empty config fails before the fix because the missing features parent table is treated as a path-not-found error.

Root Cause

For example, clearing features.personality from an empty config.toml returns configPathNotFound / Path not found because the [features] table does not exist.

Fix Action

Fixed

PR fix notes

PR #1: fix(app-server): clear_path treats absent intermediate tables as a no-op

Description (problem / solution / changelog)

Summary

Fixes openai/codex#20145.

config/value/write with value: null is the API contract for clearing/unsetting a config key. When the path points to a nested key whose parent table does not yet exist in config.toml (e.g. clearing features.personality from an empty file), clear_path was returning MergeError::PathNotFound which surfaces to callers as configPathNotFound / Path not found.

The correct behaviour is to treat it as an idempotent no-op — the value is already absent, so the clear succeeds with no file change.

Root cause — two arms in clear_path that encounter a missing intermediate table:

// before
TomlValue::Table(table) => {
    current = table.get_mut(segment).ok_or(MergeError::PathNotFound)?;
}
_ => return Err(MergeError::PathNotFound),

Fix — return Ok(false) (value unchanged) instead of propagating an error:

// after
TomlValue::Table(table) => match table.get_mut(segment) {
    Some(next) => current = next,
    None => return Ok(false),
},
_ => return Ok(false),

The as_table_mut() guard at the end of the function is updated consistently for the same reason.

Changes

  • codex-rs/app-server/src/config_manager_service.rs — fix clear_path
  • codex-rs/app-server/src/config_manager_service_tests.rs — regression test clear_missing_nested_config_is_noop

Test plan

  • New test clear_missing_nested_config_is_noop reproduces the reported failure before the fix and passes after
  • Existing write_value_* tests continue to pass
  • cargo test -p codex-app-server green

Changed files

  • codex-rs/app-server/src/config_manager_service.rs (modified, +6/-5)
  • codex-rs/app-server/src/config_manager_service_tests.rs (modified, +26/-0)

PR #20334: Make missing config clears no-ops

Description (problem / solution / changelog)

Why

Fixes #20145.

config/value/write treats a JSON null value as a request to clear the config key. Clearing a key that is already absent should be idempotent, but clearing a nested key such as features.personality from an empty config.toml returned configPathNotFound because clear_path treated the missing features parent table as an error.

That makes app-server reset flows brittle because clients have to read first and avoid sending a clear request unless the parent path already exists.

What Changed

  • Updated app-server config clearing so missing intermediate tables, or non-table parents, are treated as an unchanged no-op.
  • Removed the now-unreachable MergeError::PathNotFound path from config write merging.
  • Added a regression test covering features.personality = null against an empty user config.

Verification

  • cargo test -p codex-app-server clear_missing_nested_config_is_noop
  • cargo test -p codex-app-server was run; the config manager unit suite passed, but one unrelated integration test failed because turn_start_emits_thread_scoped_warning_notification_for_trimmed_skills expected 7 trimmed skills and observed 8.
  • just fix -p codex-app-server

Changed files

  • codex-rs/app-server/src/config_manager_service.rs (modified, +6/-8)
  • codex-rs/app-server/src/config_manager_service_tests.rs (modified, +24/-0)

Code Example

{
  "keyPath": "features.personality",
  "value": null,
  "mergeStrategy": "replace"
}

---

configPathNotFound / Path not found
RAW_BUFFERClick to expand / collapse

What issue are you seeing?

config/value/write appears to treat JSON null as a clear/unset operation, but clearing a missing nested config value currently fails when an intermediate parent table is absent.

For example, clearing features.personality from an empty config.toml returns configPathNotFound / Path not found because the [features] table does not exist.

This makes reset/clear flows brittle for app-server clients, since a client has to distinguish between “value exists” and “value is already absent” before sending an otherwise idempotent clear.

What steps can reproduce the bug?

Start with an empty user config.toml.

Call config/value/write with:

{
  "keyPath": "features.personality",
  "value": null,
  "mergeStrategy": "replace"
}

Actual result:

configPathNotFound / Path not found

I reproduced this locally with a focused regression test against ConfigManager::write_value: clearing features.personality from an empty config fails before the fix because the missing features parent table is treated as a path-not-found error.

What is the expected behavior?

Clearing an already-unset nested config value should succeed as an idempotent no-op.

The response should be successful, the config file should remain unchanged, and config/value/write should not return configPathNotFound just because the parent table is absent.

Additional information

I searched for existing issues/PRs using terms such as config/value/write, configPathNotFound, ConfigPathNotFound, features.personality, null, and clear missing nested config path, and I did not find an exact duplicate.

Related but different issues I found include #10499 and #11728, but those appear to cover different config-write failure modes.

I have a small regression test and narrow fix direction prepared if maintainers agree this should be treated as a no-op.

extent analysis

TL;DR

Modify the config/value/write endpoint to treat clearing a missing nested config value as an idempotent no-op when the intermediate parent table is absent.

Guidance

  • Review the ConfigManager::write_value method to handle the case where the parent table is missing and the value to be cleared is null.
  • Update the logic to check if the parent table exists before attempting to clear the value, and if not, return a successful response without modifying the config file.
  • Consider adding a test case to cover this specific scenario to ensure the fix is correct and prevent regressions.
  • Evaluate the mergeStrategy parameter to ensure it is correctly handled in this case, potentially allowing for a replace strategy to be applied even if the parent table is absent.

Example

// Example request to clear a nested config value
{
  "keyPath": "features.personality",
  "value": null,
  "mergeStrategy": "replace"
}
// Expected response: successful, without modifying the config file

Notes

The current implementation of config/value/write returns a configPathNotFound error when attempting to clear a missing nested config value, which can cause issues for app-server clients. The proposed fix aims to make the endpoint more robust by treating this case as an idempotent no-op.

Recommendation

Apply a workaround to modify the config/value/write endpoint to handle the case where the parent table is missing and the value to be cleared is null, as this will provide a more robust and idempotent behavior for app-server clients.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING