Skip to content

fix: preserve JSON object key order in proxied payloads - #439

Open
himorishige wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
himorishige:fix/preserve-json-key-order
Open

fix: preserve JSON object key order in proxied payloads#439
himorishige wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
himorishige:fix/preserve-json-key-order

Conversation

@himorishige

@himorishige himorishige commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #438.

What

Enables serde_json's preserve_order feature for the workspace, so JSON objects in proxied payloads are forwarded with their keys in the order the client sent them instead of alphabetized (the BTreeMap default). One line in Cargo.toml, plus the lockfile update (indexmap was already in the dependency tree).

Why

Object key order is semantic for response_format.json_schema: order-enforcing structured-output backends (vLLM with its default xgrammar backend) use the properties declaration order as the generation order. The router currently re-serializes every object with alphabetized keys, silently changing what downstream models are forced to generate. A model-independent repro is in #438.

With an order-sensitive fine-tuned judge behind an llm_classifier route we measured an 18% judgment-runaway rate (grammar/EOS whitespace deadlock at max_tokens, each occurrence an invalid verdict and a fail-open); restoring key order drops it to zero.

Verification

  • cargo test --workspace passes with the feature enabled
  • Passthrough probe: a schema sent as zebra/apple/mango reaches the backend in that order (previously apple/mango/zebra)
  • E2E: an identical 100-judgment probe through the router against a local vLLM target went from 36/200 runaways — with all 10 request shapes flipping between tiers across reruns — to 0 runaways and 0 flips once key order is preserved

Notes

  • preserve_order swaps serde_json's Map backing to IndexMap workspace-wide. Anything relying on alphabetical serialization would change behavior; the test suite passes, and for a proxy, forwarding payloads unmodified seems the safer default.
  • Array order was already preserved; only object keys were affected.
  • If you'd rather avoid the workspace-wide feature (e.g., carry passthrough JSON as RawValue instead), happy to rework.

Summary by CodeRabbit

  • Improvements
    • JSON object fields now retain their original order when processed and displayed, providing more consistent and predictable output.

serde_json's default Map is BTreeMap-backed, so every JSON object that
passes through the router is re-serialized with alphabetized keys. Object
key order is semantic for response_format.json_schema: order-enforcing
structured-output backends (vLLM/xgrammar) use the properties declaration
order as the generation order, so reordering silently changes what
downstream models are forced to generate.

Enable serde_json's preserve_order feature so payloads are forwarded with
keys in the order the client sent them. Array order was already preserved.

Signed-off-by: Hiroshi Morishige <hiroshi.morishige@gmail.com>
@himorishige
himorishige requested a review from a team as a code owner August 15, 2026 09:35
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 20036233-9305-4f2a-8d81-409a73be172a

📥 Commits

Reviewing files that changed from the base of the PR and between 9ad6744 and e43d8ea.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !Cargo.lock
📒 Files selected for processing (1)
  • Cargo.toml

Walkthrough

The workspace enables serde_json's preserve_order feature. JSON object keys now retain their input order during serialization.

Changes

JSON order preservation

Layer / File(s) Summary
Enable serde_json order preservation
Cargo.toml
The workspace dependency enables serde_json's preserve_order feature while retaining version 1.

Estimated code review effort: 1 (Trivial) | ~2 minutes

Merge Risk: ⚪ Minimal · up to e43d8

This localized dependency configuration change preserves client-supplied JSON object key order, with the stated workspace tests and verification passing; no actionable merge-blocking risk remains beyond normal checks and review.

Poem

I’m a rabbit with keys in a row,
No alphabet shuffle, no overflow.
Zebra, apple, mango stay,
In the order sent, they pass this way.
Structured JSON can now proceed,
With every field in the intended lead. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive Cargo.toml enables serde_json preserve_order as required, but Cargo.lock is excluded and its update cannot be verified. Confirm that Cargo.lock contains the dependency resolution changes for the serde_json preserve_order feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: preserving JSON object key order in proxied payloads.
Out of Scope Changes check ✅ Passed The reviewed Cargo.toml change directly supports the linked issue, and no unrelated changes are shown.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Comment @coderabbitai help to get the list of available commands.

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.

Proxied JSON payloads are re-serialized with alphabetized object keys, breaking order-enforcing structured-output backends

1 participant