Sitelet https://github.com/simplify9/SW-Mtm-api/compare/main...fix/npgsql8-dynamic-json
Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: simplify9/SW-Mtm-api
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: simplify9/SW-Mtm-api
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: fix/npgsql8-dynamic-json
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 1 commit
  • 1 file changed
  • 2 contributors

Commits on Sep 1, 2026

  1. fix(pgsql): opt into Npgsql dynamic JSON so ProfileData reads work again

    Production login returns HTTP 500:
    
      InvalidCastException: Reading as 'IEnumerable<ProfileDataItem>' is not
      supported for fields having DataTypeName 'jsonb'
      ---> NotSupportedException: Type 'IEnumerable`1' required dynamic JSON
      serialization, which requires an explicit opt-in; call 'EnableDynamicJson'
    
    Regression from #129, which moved Npgsql 5.0.10 -> 8.0.11 to fix the EF Core
    TypeLoadException. Npgsql 8 removed the implicit dynamic JSON serializer:
    mapping an arbitrary POCO collection to a json/jsonb column now requires
    EnableDynamicJson() on the data source. Three properties rely on it via
    StoreAsJson() — Tenant.ProfileData, TenantMembership.ProfileData and
    Account.ProfileData — and account.profile_data is jsonb in production.
    
    The blast radius is wider than login: UseApiKeyAsRequestContext materialises
    Account on every apikey-authenticated request, so ANY such request 500s.
    
    Startup.cs now builds a single NpgsqlDataSource with EnableDynamicJson() and
    hands it to UseNpgsql. It is built once outside the AddDbContext lambda —
    NpgsqlDataSource owns the connection pool, so constructing one per DbContext
    instance would leak pools.
    
    Verified A/B against the REAL production database, same request, same data:
    
      ghcr.io/simplify9/mtm:8.0.3   GET /api/accounts   -> 500  (8 exceptions)
                                    POST .../login      -> 500
      this build                    GET /api/accounts   -> 200  (0 exceptions,
                                                          real account data)
                                    POST .../login      -> 400  (handler reached,
                                                          bad password rejected)
    
    No schema changes were applied during the test — the 2021 migrations are
    already present, so startup migration is a no-op.
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01VHkpqv6dB6wjALyFe9ocMU
    MusaMisto and claude committed Sep 1, 2026
    Configuration menu
    Copy the full SHA
    98835db View commit details
    Browse the repository at this point in the history
Loading