Skip to content

json_tree: a stored float can come back one ulp off because numbers are re-parsed without serde_json float_roundtrip #1364

Open

Description

@coderdan

Background

EQL v4's json_tree is the encrypted JSON column type that Stack Encrypt (the Rust crate stack-encrypt) writes: one encrypted entry per JSON node, so PostgreSQL can search the document without the key. When a document is sealed, each number leaf is written into its entry's ciphertext as text (serde_json::Number::to_string, in encode_node in packages/stack-encrypt/src/json/derive.rs). When the client opens the entry, the text is parsed back into a serde_json::Number.

Problem

serde_json is built without its float_roundtrip feature. Without it, parsing a float uses a fast path that is not guaranteed to return the nearest f64, so a value can come back one unit in the last place away from the one that was stored. A property test over random f64 values found a concrete case while PR #1363 was being written: -926809.5051008083 was stored and -926809.5051008085 came back.

Who hits it: any application that stores a float with a full-precision decimal expansion in a json_tree column and reads it back through a subtree read or ->. The value is silently wrong in the last digit; nothing errors. Integers and floats with short decimal expansions are unaffected. Nothing catches it today because the existing tests use exactly representable floats, and the property test in #1363 was narrowed to them so it would pass.

Proposal

  1. Enable serde_json's float_roundtrip feature in packages/stack-encrypt/Cargo.toml (and check the other crates that parse the same text: eql-bindings, the Go and WASM guests if they re-parse numbers).
  2. Widen the property test in packages/stack-encrypt/tests/json_properties.rs back to arbitrary finite f64 values, so the test fails if the feature is ever dropped.
  3. Check whether the ordering term and the value selector derive from the parsed value anywhere on the read side; if they do, they are affected the same way.

Relationship to other work

Found while implementing #1360 in PR #1363, which does not fix it. Refs #1363.

https://claude.ai/code/session_01N7bCqa3ZVJMcEE99RzVqEu

Activity

  1. added
    bugSomething isn't working
    rustPull requests that update Rust code
    on Oct 24, 2026
  2. coderdan commented on Oct 25, 2026

    @coderdan
    ContributorAuthor

    Fixed in draft PR #1366 (serde_json float_roundtrip on stack-encrypt, with a regression test and a property test over arbitrary finite f64). https://claude.ai/code/session_01N7bCqa3ZVJMcEE99RzVqEu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    SDKbugSomething isn't workingrustPull requests that update Rust code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions