Skip to content

10.x: on Npgsql EF 10.0.3 with PostgreSQL 16 configured, the JSON-setter refusal names the column instead of the path, and gives a reason that no longer holds (jsonb_set_lax) #303

Closed

Description

@CaffeinatedCoder

Problem

Npgsql EF 10.0.3 carries npgsql/efcore.pg#3855 ("Fix JSON null partial updates", merged 2026-06-02; the function name is in the 10.0.3 assembly and in none of 10.0.0–10.0.2): an ExecuteUpdate setter inside a jsonb document is written as jsonb_set_lax(doc, path, value) when the configured PostgreSQL version is 16 or later and the value may be null. Npgsql EF 10's default assumed version is 14 (NpgsqlOptionsExtension.DefaultPostgresVersion), so a consumer meets it by calling SetPostgresVersion(16, 0) — the floor the 10.x packages document.

ValueSetSqlGuard on release/10.x matches jsonb_set and json_set only. Under jsonb_set_lax the refusal of a value set written through to_jsonb still fires — it is keyed off to_jsonb, so it fails closed and nothing is written — but it names the JSON column ('Doc') instead of the property path ('Doc.Tags', 'Doc.Nested.Flags'), and the null half of its message gives a reason that does not hold under jsonb_set_lax, which sets the property to JSON null where jsonb_set returned NULL for the whole document (#289 measured this on PostgreSQL 16). Same as #289 on the 11 line.

Measured 2026-10-19 on release/10.x (d47d9a3) with the test host resolving EF Core 10.0.13 / Npgsql EF 10.0.3 and UpdateTestContext configured with .SetPostgresVersion(16, 0): 6 of 7 ExecuteUpdateGuardTests fail on the path in the message — ANullParameter_IsRefusedForWhatNullDoes, ANullConstant_IsRefusedForWhatNullDoes, ANullableColumn_IsRefusedForBothOutcomes, AConditionalWithANullBranch_IsRefusedForBothOutcomes, AValueSetInsideAJsonColumn_IsRefused, AValueSetInANestedComplexTypeOfAJsonColumn_IsRefused — and every one still throws. Without SetPostgresVersion all 7 pass on the same versions, which is why the suites did not see it (#297). Cosmetic: nothing is written that was refused before.

Change

Port the #289 fix from PR #292: match jsonb_set_lax too; drop the "writes NULL as the whole document" reason and the MayBeNull distinction; the null refusal names 42804; docs/efcore.md's JSON-column table says the same. Still refused in every case it was. The guard tests run with the PostgreSQL version set to 16 as well as unset, so the jsonb_set and the jsonb_set_lax shape are both asserted on the 10.x floor and on the newest patch. Hand-extracted commit naming PR #292.

The port also carries #292's NULLIF arm. EF Core 10 already writes a == b ? null : a as NULLIF(a, b) (measured 2026-10-19 on EF Core 10.0.0 and 10.0.13), and over a value set Union computed on the server the refusal named no operation ("This use of it") where it should name value set equality. It was refused either way, so this is cosmetic too; NullIf_OverAServerSideUnion_IsRefusedAsEquality fails without the arm on the floor and on the newest patch.

Measured on PostgreSQL 16 with the refusal disabled: Npgsql EF 10.0.0 writes jsonb_set with the version unset and with 16, and its may-be-null value still writes NULL as the whole document (23502); Npgsql EF 10.0.3 writes jsonb_set(…, COALESCE(to_jsonb(…), 'null'::jsonb)) with the version unset and jsonb_set_lax with 16, and both write JSON null. The dropped reason is true on 10.0.0–10.0.2 only; the JSON array refusal holds on every patch.

Done when

On release/10.x, ExecuteUpdateGuardTests pass on Npgsql EF 10.0.0 with the version unset and on Npgsql EF 10.0.3 with SetPostgresVersion(16, 0), every refusal naming the property path, and reverting the port fails the six tests on the latter only.

Activity

  1. added this to the 10.0.1 milestone on Oct 19, 2026
  2. added
    bugSomething isn't working
    area/value-setsValue set families and wrapper arities
    package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
    severity/lowCosmetic, message or documentation-level difference
    on Oct 19, 2026
  3. CaffeinatedCoder commented on Oct 19, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Fixed on release/10.x by PR #313 (merge commit 07878a0, 2026-10-19). Closed by hand: Closes acts only on main, where the fix arrived with PR #292 (#289).

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

    area/value-setsValue set families and wrapper aritiesbugSomething isn't workingpackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLseverity/lowCosmetic, message or documentation-level difference

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions