Skip to content

fix(cli): omit null/empty request fields so older instances accept them#2799

Merged
ZaynJarvis merged 1 commit into
volcengine:mainfrom
t0saki:fix/cli-skip-null-request-fields
Jun 24, 2026
Merged

fix(cli): omit null/empty request fields so older instances accept them#2799
ZaynJarvis merged 1 commit into
volcengine:mainfrom
t0saki:fix/cli-skip-null-request-fields

Conversation

@t0saki

@t0saki t0saki commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

The CLI unconditionally attaches optional fields to the find / search / add_resource request bodies — args as an empty {}, and tags / context_type as null — even when the user never set them. Because OpenViking kernels declare model_config = ConfigDict(extra="forbid") on these routes, any instance that predates a given field rejects the entire request with body.<field>: Extra inputs are not permitted. This patch stops sending those empty/null fields, and turns the raw rejection into an actionable hint when a field really is set but unsupported.

Problem

The breakage is purely a field-set mismatch on extra="forbid" routes: the set of fields the CLI sends must be a subset of the fields the target instance's model defines. It is not strictly "CLI newer than server" — it bites in both directions (newer CLI sending a not-yet-added field, or older CLI still sending a field the kernel later renamed/removed).

Concrete cases observed against the Volcengine endpoint (same gateway, different instance versions selected by API key):

Fix

  • Add compact_request_body() and apply it in find / search / add_resource: drop null-valued keys and an empty args object right before sending. Scoped to these read/create routes only, where a missing optional field and an explicit null are equivalent — deliberately not applied globally in post, since null may carry "clear this field" semantics on a future update/PATCH route. This generalizes the backward-compat convention already used for create_parent.
  • When a field is explicitly set but the instance does not support it, detect the pydantic Extra inputs are not permitted rejection (extra_forbidden_field) and render a version-mismatch hint instead of the opaque API error, plus an ov health action to check the instance version.

Verification

  • New unit tests: compact_request_body_drops_null_and_empty_args, compact_request_body_keeps_non_empty_args, extracts_extra_forbidden_field, ignores_non_extra_forbidden_errors — all pass.
  • cargo test -p ov_cli --bins: all tests pass except one pre-existing failure (help_ui … missing clap command set-tags) that is unrelated to this change and reproduces on main with this patch stashed.
  • End-to-end: a debug build of the patched CLI now returns results for ov find against an instance that previously failed with body.tags: Extra inputs are not permitted.

The CLI unconditionally attaches optional fields to the find/search/add_resource
request bodies — `args` as an empty `{}` and `tags`/`context_type` as `null` —
even when the user never set them. OpenViking kernels use
`model_config = ConfigDict(extra="forbid")` on these routes, so any instance that
predates a field rejects the whole request with
`body.<field>: Extra inputs are not permitted`. This breaks whenever the CLI is
newer than the target instance (and, symmetrically, when a field is later
renamed/removed): e.g. `ov add-resource` fails on `body.args` against a pre-volcengine#2549
instance, and `ov find` fails on `body.tags` against a strict pre-volcengine#2706 instance.

- Add `compact_request_body()` and apply it in find/search/add_resource: drop
  null-valued keys and an empty `args` object before sending. Scoped to these
  read/create routes only, where a missing optional field and an explicit null
  are equivalent — not applied globally, since null may mean "clear" on a future
  update/PATCH route. This mirrors the existing `create_parent` backward-compat
  convention.
- When a field is explicitly set but unsupported, translate the raw pydantic
  `Extra inputs are not permitted` error into a version-mismatch hint and suggest
  `ov health`, instead of surfacing the opaque API error.

Tests: unit tests for `compact_request_body` and `extra_forbidden_field`.

@ZaynJarvis ZaynJarvis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm, fixes compatibility issue

@ZaynJarvis ZaynJarvis merged commit 2af4d74 into volcengine:main Jun 24, 2026
9 of 10 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in OpenViking project Jun 24, 2026
t0saki added a commit that referenced this pull request Jun 25, 2026
…em (#2834)

The Python SDK's find/search/add_resource unconditionally attach optional
fields to their request bodies — `args` as an empty `{}` and
`tags`/`score_threshold`/`filter`/`context_type`/`session_id` as `null` — even
when the caller never set them. OpenViking kernels use
`model_config = ConfigDict(extra="forbid")` on these routes, so any instance
that predates a field rejects the whole request with
`body.<field>: Extra inputs are not permitted`. This breaks the SDK (and every
SDK consumer, e.g. vikingbot via `ov.AsyncHTTPClient`) against older instances:
`add_resource` fails on `body.args` against a pre-#2549 instance, and `find`
fails on `body.tags` against a strict pre-#2706 instance.

This is the SDK-side counterpart of #2799, which fixed the same anti-pattern in
the Rust CLI but left the Python SDK untouched.

- Add `_compact_request_body()` and apply it in find/search/add_resource: drop
  null-valued keys and an empty `args` object before sending. Scoped to these
  read/create routes only, where a missing optional field and an explicit null
  are equivalent — not applied globally, since null may mean "clear" on a future
  update/PATCH route. Mirrors the CLI's `compact_request_body`.

Tests: unit tests for `_compact_request_body` and for find/search/add_resource
omitting unset optional fields while keeping explicitly-provided ones.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants