Skip to content

[rust] fix: free-form object query parameters reference a nonexistent models::serde_json - #24866

Open
wiebren wants to merge 2 commits into
OpenAPITools:masterfrom
wiebren:fix/rust-free-form-object-query-parameter
Open

[rust] fix: free-form object query parameters reference a nonexistent models::serde_json#24866
wiebren wants to merge 2 commits into
OpenAPITools:masterfrom
wiebren:fix/rust-free-form-object-query-parameter

Conversation

@wiebren

@wiebren wiebren commented Sep 4, 2026

Copy link
Copy Markdown

A free-form object parameter — type: object with no properties — is typed
Option<models::serde_json::Value> in every generated api module, but models re-exports no
serde_json, so the crate fails to compile with one E0433 per operation that uses one:

parameters:
  - in: query
    name: filter
    schema:
      type: object
pub async fn list_things(configuration: &configuration::Configuration, filter: Option<models::serde_json::Value>, ...)
error[E0433]: failed to resolve: could not find `serde_json` in `models`

Free-form body parameters are typed serde_json::Value and compile fine; only query, path,
and header parameters are affected. All four rust client libraries (reqwest, reqwest-trait,
hyper, hyper0x) share the bug.

The cause

The api templates qualify a parameter's type with models:: unless it is a string, uuid,
primitive, or container — rust/reqwest/api.mustache and the same pattern in the other three
libraries:

{{^isString}}{{^isUuid}}{{^isPrimitiveType}}{{^isContainer}}models::{{/isContainer}}{{/isPrimitiveType}}{{{dataType}}}{{/isUuid}}{{/isString}}

A free-form object maps to serde_json::Value (typeMapping.put("object", "serde_json::Value")),
which lives outside models. Body parameters escape because
DefaultCodegen.updateRequestBodyForObject marks free-form bodies isPrimitiveType = true,
while fromParameter sets only isFreeFormObject — so the prefix lands on non-body parameters.

The fix

RustClientCodegen.postProcessOperationsWithModels now marks free-form, non-container
parameters as primitive — the treatment free-form bodies already get — right next to the
existing isAnyType special case. One codegen change covers all four libraries' templates.

Non-container matters: a free-form schema with additionalProperties is typed
HashMap<String, …>, is already exempt from the prefix as a container, and must keep its
serde_json::to_string query serialization since HashMap has no Display.

Wire behavior is unchanged: the query serialization branch for these parameters is chosen by
isObject/isMap/isDeepObject, not isPrimitiveType, and the required-parameter path
always used .to_string() (for serde_json::Value, Display is its JSON serialization).

Tests

RustClientCodegenTest#testFreeFormObjectQueryParam, generating from the new fixture
3_0/rust/free-form-object-query-param.yaml, locks in:

  • filter: Option<serde_json::Value> and no models::serde_json anywhere;
  • type: object with typed additionalProperties staying HashMap<String, String>;
  • additionalProperties: true (free-form and a map) staying
    HashMap<String, serde_json::Value> with serde_json::to_string serialization.

It fails without the main/ change.

Verified by compiling generated clients

Clients generated from a spec with optional, required, and map-typed object query parameters:

library cargo build
reqwest (sync) clean
reqwest (async) clean
hyper clean
reqwest-trait clean for the free-form parameters this PR touches

Two adjacent breakages exist identically on master and in v7.15.0, i.e. before this change,
and are left out of scope: reqwest-trait calls .to_string() on map-typed query
parameters (which this PR does not touch), and the exploded style: deepObject free-form
branch iterates a serde_json::Value (.len()/.iter()), which does not compile either way.

PR checklist


Generated with Claude Code


Summary by cubic

Fixes generated Rust clients failing to compile when an operation uses a free-form object query, path, or header parameter. These were typed models::serde_json::Value, which doesn't exist; they're now serde_json::Value, matching free-form body parameters.

  • One codegen change covers all four Rust generators (reqwest, reqwest-trait, hyper, hyper0x).
  • Free-form objects with additionalProperties stay HashMap-typed and keep their existing query serialization; no wire behavior changes.
  • Adds a regression test covering plain, typed-map, and additionalProperties: true free-form object query parameters.

Written for commit 1a9f875. Summary will update on new commits.

Review in cubic

…t models::serde_json::Value

A free-form object parameter (type: object with no properties) maps to
serde_json::Value, but the api templates qualify every non-primitive,
non-container parameter type with models:: - and models re-exports no
serde_json, so the generated crate fails with E0433. Free-form body
parameters already avoid this because updateRequestBodyForObject marks
them primitive; give non-body free-form parameters the same treatment.
Free-form schemas with additionalProperties stay containers (HashMap)
and keep their JSON serialization.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CxDNCjqJycKTfzVWg2SeTJ

@cubic-dev-ai cubic-dev-ai Bot 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.

No issues found across 3 files

Re-trigger cubic

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.

1 participant