Conversation
HashMap implements neither Display nor ToString, so the generated client did not compile (E0599) wherever a map-typed query parameter fell through to the scalar path: a required non-nullable map in both reqwest and reqwest-trait, and the nullable/optional non-deepObject fallthroughs in reqwest-trait. Serialize the map as one json-encoded parameter with serde_json::to_string, exactly how reqwest's optional branch already handles non-primitive parameters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GcwZ1arjLZNpetHz2a3TJz
There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache">
<violation number="1" location="modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache:170">
P3: A required, non-nullable map declared with `style: deepObject` falls into this `{{#isMap}}` branch and is serialized as a single JSON-encoded parameter (`labels={...}`) instead of the deep-object `labels[key]=value` form. The template only implements deepObject spreading inside the `{{#isNullable}}` branch, so required non-nullable deep-object maps bypass it. Previously this path emitted `.to_string()` and did not compile, so this is an incomplete fix, not a regression, but the wire format is now silently wrong for that style.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| {{^isArray}} | ||
| {{^isNullable}} | ||
| {{#isMap}} | ||
| req_builder = req_builder.query(&[("{{{baseName}}}", &serde_json::to_string(&{{{vendorExtensions.x-rust-param-identifier}}})?)]); |
There was a problem hiding this comment.
P3: A required, non-nullable map declared with style: deepObject falls into this {{#isMap}} branch and is serialized as a single JSON-encoded parameter (labels={...}) instead of the deep-object labels[key]=value form. The template only implements deepObject spreading inside the {{#isNullable}} branch, so required non-nullable deep-object maps bypass it. Previously this path emitted .to_string() and did not compile, so this is an incomplete fix, not a regression, but the wire format is now silently wrong for that style.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache, line 170:
<comment>A required, non-nullable map declared with `style: deepObject` falls into this `{{#isMap}}` branch and is serialized as a single JSON-encoded parameter (`labels={...}`) instead of the deep-object `labels[key]=value` form. The template only implements deepObject spreading inside the `{{#isNullable}}` branch, so required non-nullable deep-object maps bypass it. Previously this path emitted `.to_string()` and did not compile, so this is an incomplete fix, not a regression, but the wire format is now silently wrong for that style.</comment>
<file context>
@@ -166,7 +166,12 @@ pub {{#supportAsync}}async {{/supportAsync}}fn {{{operationId}}}(configuration:
{{^isArray}}
{{^isNullable}}
+ {{#isMap}}
+ req_builder = req_builder.query(&[("{{{baseName}}}", &serde_json::to_string(&{{{vendorExtensions.x-rust-param-identifier}}})?)]);
+ {{/isMap}}
+ {{^isMap}}
</file context>
There was a problem hiding this comment.
Accurate, and worth separating from this PR's scope. That branch - required, non-nullable - has never had any isDeepObject handling at all: unlike the nullable and optional paths just below it, it goes straight to the scalar form for every type. So a required non-nullable style: deepObject map was not previously exploded either; it did not compile at all, which is what this PR fixes. The json encoding it now produces is the same shape the other libraries' non-primitive parameters use, so nothing regresses - but you are right that it is not the declared style.
The deepObject format work lives in #24899, which routes exploded deepObject maps through parse_deep_object (both the free-form and the typed-map shape). Extending that to the required non-nullable branch is a small addition and I am happy to push it - I would suggest doing it there rather than here, so all deepObject encoding stays in one PR and these two do not both edit the same template lines. Say which you prefer and I will add it.
`serde_json::to_string(&` matched any call in the file; match on the `labels` key instead, which both libraries emit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ait-map-query-params # Conflicts: # modules/openapi-generator/src/test/java/org/openapitools/codegen/rust/RustClientCodegenTest.java
A map-typed query parameter (
type: objectwith typedadditionalProperties, generated asHashMap<String, T>) falls through to the scalar path in several template branches, which call.to_string()on it.HashMaphas noDisplay, so the crate does not compile:.to_string(): broken.to_string(): broken.to_string()fallthrough: broken.to_string()fallthrough: brokenFix
An
{{#isMap}}split at each hole serializes the map withserde_json::to_string, as reqwest's optional non-primitive branch already does. No wire change for anything that compiled before:isMapalso covers a bare free-form object (serde_json::Value), which moves from.to_string()toserde_json::to_string(..)?, and those produce the same JSON.Verification
RustClientCodegenTest#testMapQueryParamsSerializeAsJsonruns the fixture through both libraries and fails without the templates.cargo buildis clean with the fix and fails with E0599 without it.Known gaps
A required non-nullable
style: deepObjectmap is sent as one JSON parameter. That branch never had deepObject handling (for maps it did not compile before); deepObject serialization is #24899's scope.Related
Follow-up to #24866.
PR checklist
./bin/generate-samples.sh ./bin/configs/rust-*): zero diffs.Summary by cubic
Fixes Rust client codegen for map-typed query parameters, which previously emitted
.to_string()on aHashMap(it has noDisplay/ToString) and failed to compile inreqwestandreqwest-trait. Maps now serialize as a single JSON-encoded query parameter viaserde_json::to_string, matching how non-primitive parameters are already handled. No behavior change for parameters that compiled before.style: deepObjectmap still sends as one JSON parameter; deepObject serialization remains out of scope.Written for commit 5fb96ef. Summary will update on new commits.
Generated with Claude Code