Source
Sentry: https://sentry.tinyhumans.ai/organizations/tinyhumans/issues/9253/ (TAURI-RUST-85R)
Events: 2,037 · Users affected: 5 · First seen: 2026-06-01 · Last seen: 2026-06-26 (still firing on 0.57.18)
Symptom
nvidia response parse error: duplicate field `reasoning_content` at line 1 column 742 — the entire completion is dropped.
Root cause
NVIDIA's OpenAI-compat endpoint returns a message object containing the key reasoning_content twice in the same object (a known quirk of some compat proxies for thinking models, e.g. stepfun-ai/step-3.7-flash). ResponseMessage has a hand-written Deserialize impl (compatible_types.rs:347) whose inner Shadow struct uses serde's derived deserializer with a single reasoning_content: Option<String> field — serde strict-rejects a repeated key (#[serde(default)] does not relax this), so the whole response fails to parse. Prior #3547/#3552 only fixed the distinct-name collision (reasoning + reasoning_content), not two identical keys. StreamDelta::deserialize (compatible_types.rs:507) has the same latent gap on the SSE path. Parse sites: compatible_provider_impl.rs:848 (buffered, the event) and compatible_stream_native.rs:198 (SSE fallback).
Bucket / RCA
real-defect / broken-parsing-contract — a deserialize failure on valid (if quirky) provider output drops the completion. NOT a demote candidate; parsing must succeed. RCA fix: tolerate duplicate reasoning_content (last-wins / fold), e.g. deserialize via serde_json::Value/Map or a custom visitor that folds reasoning_content (+ reasoning alias) into the single canonical field — preserving "canonical wins". Apply to both ResponseMessage and StreamDelta.
Dedupe
NEW (residual after #3547; not covered). No open PR / GH issue. Unrelated to our #4182-4189.
Suggested scope
No AI-attribution trailers in commits/PR. Do NOT run local cargo — push --no-verify and let PR CI test.
Source
Sentry: https://sentry.tinyhumans.ai/organizations/tinyhumans/issues/9253/ (TAURI-RUST-85R)
Events: 2,037 · Users affected: 5 · First seen: 2026-06-01 · Last seen: 2026-06-26 (still firing on 0.57.18)
Symptom
nvidia response parse error: duplicate field `reasoning_content` at line 1 column 742— the entire completion is dropped.Root cause
NVIDIA's OpenAI-compat endpoint returns a
messageobject containing the keyreasoning_contenttwice in the same object (a known quirk of some compat proxies for thinking models, e.g.stepfun-ai/step-3.7-flash).ResponseMessagehas a hand-writtenDeserializeimpl (compatible_types.rs:347) whose innerShadowstruct uses serde's derived deserializer with a singlereasoning_content: Option<String>field — serde strict-rejects a repeated key (#[serde(default)]does not relax this), so the whole response fails to parse. Prior #3547/#3552 only fixed the distinct-name collision (reasoning+reasoning_content), not two identical keys.StreamDelta::deserialize(compatible_types.rs:507) has the same latent gap on the SSE path. Parse sites:compatible_provider_impl.rs:848(buffered, the event) andcompatible_stream_native.rs:198(SSE fallback).Bucket / RCA
real-defect/ broken-parsing-contract — a deserialize failure on valid (if quirky) provider output drops the completion. NOT a demote candidate; parsing must succeed. RCA fix: tolerate duplicatereasoning_content(last-wins / fold), e.g. deserialize viaserde_json::Value/Mapor a custom visitor that foldsreasoning_content(+reasoningalias) into the single canonical field — preserving "canonical wins". Apply to bothResponseMessageandStreamDelta.Dedupe
NEW (residual after #3547; not covered). No open PR / GH issue. Unrelated to our #4182-4189.
Suggested scope
src/openhuman/inference/provider/compatible_types.rs—ResponseMessage::deserialize(~347-375) andStreamDelta::deserialize(~507-530): tolerate duplicatereasoning_contentkeys.message/deltaJSON with tworeasoning_contentkeys parses successfully (alongside the existing Custom provider response parse fails: duplicate fieldreasoning_contentwhen provider emits bothreasoningandreasoning_content#3547 reasoning+reasoning_content test).No AI-attribution trailers in commits/PR. Do NOT run local cargo — push --no-verify and let PR CI test.