Skip to content

fix: work around pydantic-settings 2.13.0 nested subcommand bug (ENG-6707) - #49

Merged
johnsca merged 5 commits into
mainfrom
johnsca/fix/ENG-6707/pydantic-settings-2.13.0-error
Feb 23, 2026
Merged

johnsca merged 5 commits into
mainfrom
johnsca/fix/ENG-6707/pydantic-settings-2.13.0-error

Conversation

@johnsca

@johnsca johnsca commented Feb 20, 2026 •

Copy link
Copy Markdown
Contributor

ENG-6707

What

  • Replace CliApp.run_subcommand(self) in AgentConfigCommand.cli_cmd with get_subcommand(self, is_required=True).cli_cmd()
  • Pin pydantic-settings to >=2.13.0,<2.14.0

Why

  • pydantic-settings 2.13.0 rewrote run_subcommand to navigate _parser_map via a _subcommand_stack. When computing the nested subcommand_dest key it applies get_kebab_case() to preferred_alias (snake_case field name), converting e.g. agent_config → agent-config. But _parser_map is keyed using the raw arg.dest which preserves snake_case. With cli_kebab_case=True on CLIArguments, the lookup fails with KeyError: <class AgentConfigGenerateCommand> when dispatching the third-level subcommand.
  • get_subcommand finds the active subcommand field directly without using _parser_map, bypassing the broken navigation entirely.

Testing

  • All 211 existing tests pass
  • Manual confirmation with new library version:
❯ just install
Resolved 105 packages in 871ms
      Built stacklet-mcp @ file:///Users/cory/stacklet/mcp-server
Prepared 2 packages in 100ms
Uninstalled 2 packages in 17ms
Installed 2 packages in 3ms
 - pydantic-settings==2.11.0
 + pydantic-settings==2.13.1
 ~ stacklet-mcp==2025.11.0 (from file:///Users/cory/stacklet/mcp-server)
just run agent-config generate default > .mcp.json
uv run stacklet-mcp agent-config generate default
Wrote .mcp.json

Docs

N/A

…6707)

[ENG-6707](https://stacklet.atlassian.net/browse/ENG-6707)

What
----

- Replace `CliApp.run_subcommand(self)` in `AgentConfigCommand.cli_cmd` with `get_subcommand(self, is_required=True).cli_cmd()`
- Pin pydantic-settings to `>=2.13.0,<2.14.0`

Why
---

- pydantic-settings 2.13.0 rewrote `run_subcommand` to navigate `_parser_map` via a `_subcommand_stack`. When computing the nested `subcommand_dest` key it applies `get_kebab_case()` to `preferred_alias` (snake_case field name), converting e.g. `agent_config` → `agent-config`. But `_parser_map` is keyed using the raw `arg.dest` which preserves snake_case. With `cli_kebab_case=True` on `CLIArguments`, the lookup fails with `KeyError: <class AgentConfigGenerateCommand>` when dispatching the third-level subcommand.
- `get_subcommand` finds the active subcommand field directly without using `_parser_map`, bypassing the broken navigation entirely.

Testing
-------

- [x] All 211 existing tests pass

Docs
----

N/A

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@johnsca
johnsca requested a review from a team as a code owner February 20, 2026 21:31

@jtroup jtroup left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks @johnsca

@fwereade fwereade left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as well, but could we also update the

__version__ = "2026.02.0"

then once that's all landed we can just tag-release and (hopefully) fix everybody

@fwereade fwereade left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks

@johnsca
johnsca merged commit b9a2bda into main Feb 23, 2026
5 checks passed
@johnsca
johnsca deleted the johnsca/fix/ENG-6707/pydantic-settings-2.13.0-error branch February 23, 2026 15:54
sampsre added a commit that referenced this pull request Oct 30, 2026
### what

Relax pydantic-settings from `>=2.13,<2.14` to `>=2.13,<2.15` and update
the lockfile to 2.14.2. Retain support for 2.13 and the direct
nested-command dispatch introduced in #49. Keep 2.15 and later excluded
pending validation.

Update the Python and uv tool pins to 3.12.16 and 0.13.6.

### why

Chainlit 2.12 requires pydantic-settings >=2.14.2, so the current cap
prevents it from sharing an environment with stacklet-mcp. The existing
CLI workaround remains compatible with 2.14.2. This allows
stacklet/platform#5404 to replace its temporary dependency override
after this change merges.

CI's shared bootstrap fails before lint or tests because Python 3.12.10
has no build for the current Ubuntu 26.04 runner. Python 3.12.16 has a
supported build; uv 0.13.6 also knows how to provision that release.

### testing

- `just test-coverage`: 258 passed on Python 3.12.16, with 98.40%
coverage, including nested CLI commands and settings.
- `just lint`, `uv lock --check` and `git diff --check` passed.
- `uv pip compile` resolved the candidate package alongside Chainlit
2.12.0 and pydantic-settings 2.14.2 without overrides.

### docs

Added a compatibility note under Next Release in NEWS.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants