Skip to content

fix(protocol): preserve explicit null results in ResponseFrame - #287

Merged
iuyo5678 merged 4 commits into
Tencent:mainfrom
cyberspace-cs:fix/ipc-explicit-null-result
Sep 27, 2026
Merged

iuyo5678 merged 4 commits into
Tencent:mainfrom
cyberspace-cs:fix/ipc-explicit-null-result

Conversation

@cyberspace-cs

@cyberspace-cs cyberspace-cs commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Directly deserializing {"id":"x","result":null} as ResponseFrame previously rejected a valid success response, including one produced by serializing ResponseBody::Ok(Value::Null). Preserve the presence of the result field so explicit null decodes successfully, while responses with neither field, both fields, or a null error are rejected.

The change is scoped to ResponseFrame decoding, regression tests, and the changelog. Tests cover explicit null, serialization round trips, missing and conflicting fields, duplicate result fields, invalid null errors, and compatibility with Frame, non-null results, and error responses.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --offline --locked -- -D warnings
  • cargo test --offline --locked -p bsk-protocol — 164 passed
  • CARGO_NET_OFFLINE=true node scripts/check-crate-skill.mjs
  • cargo test --workspace --offline --locked — 771 passed, 0 failed, 1 ignored (macOS)
  • GitHub CI and the open-source scan — all 8 checks passed on 5c0bb72.

The IPC protocol is JSON-RPC-style: a successful reply carries
"result" and a failed reply carries "error". Two defects made JSON
null a silent failure channel instead of a legal value.

1. Decoder (bsk-protocol): ResponseFrame::deserialize and the Frame
   visitor modelled the result field as Option<Value>, which serde
   collapses "result": null into the same None as a missing field.
   The daemon emits exactly that shape through its
   serde_json::to_value(..).unwrap_or(Value::Null) fallback, so a
   result serialisation failure surfaced on the CLI as a misleading
   "ambiguous response" / "expected result or error" decode error
   instead of a null result. Both deserializers now parse the raw
   value with #[serde(default, deserialize_with)] so an explicit
   null result decodes to Ok(Value::Null) while a missing field
   stays an error.

2. Daemon (bsk-cli): every serde_json::to_value(..).unwrap_or(Value::Null)
   site silently degraded a result serialisation failure (e.g. a
   payload nesting deeper than serde_json's recursion limit) to JSON
   null, hiding the real failure and colliding with legitimate null
   results. These now route through ok_value()/serialise_err()
   helpers that return a structured protocol_error instead, and the
   upload/download param staging paths return the same error rather
   than forwarding null params to the extension.

Adds unit tests on both sides: explicit-null decode for Frame and
ResponseFrame, serialise round-trip symmetry, missing-field
regression, and the daemon-side serialisation-failure path.
@iuyo5678

Copy link
Copy Markdown
Collaborator

Could you narrow this PR to the ResponseFrame explicit-null decoding fix and its regression tests?
The existing FrameVisitor already preserves explicit null through Some(map.next_value()?), and production IPC clients decode through Frame, so please leave that implementation unchanged.
Please defer the daemon serialization error-handling changes to a separate PR. They have defensive value, but the current description does not establish a production failure scenario. The claimed 128-level limit also applies to JSON deserialization, not serde_json::to_value().
Please update the description and changelog accordingly. We can revisit merging once the PR is scoped down.

@iuyo5678 iuyo5678 changed the title fix(ipc): decode explicit null results and stop silent null degradation fix(protocol): preserve explicit null results in ResponseFrame Sep 27, 2026
@iuyo5678
iuyo5678 merged commit 8ca7911 into Tencent:main Sep 27, 2026
8 checks passed
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.

2 participants