mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-05 04:14:21 +00:00
91643f6888
The background NodeTrafficSyncJob (every 5s) started failing after a
successful POST /panel/api/inbounds/update/{id} (including flows that
inject streamSettings.externalProxy) with:
node traffic sync: merge for <node> failed:
ERROR: CASE types boolean and integer cannot be matched (SQLSTATE 42804)
Root cause:
- The merge lives in setRemoteTrafficLocked (called from SetRemoteTraffic).
- The client_traffics delta path used a dialect-sensitive expression:
enable = enable AND ?
last_online = GREATEST(last_online, ?)
- On PostgreSQL, GREATEST / AND / COALESCE are implemented with internal
CASE expressions. When "enable" columns (client_traffics, inbounds, ...)
were INTEGER (common after SQLite → PG data migrations, older
AutoMigrate, or mixed write paths) and the right-hand side was a
boolean parameter (from snapshot ClientStats or form-bound API payload),
PG rejected the expression at plan time.
- The public API update path (unlike the internal remote wire path)
always runs updateClientTraffics + UpdateClientStat + SyncInbound.
This touches client_traffics.enable rows for any inbound that has
clients.
- SQLite tolerated 0/1 numeric bools; PG is strict.
Fix:
- Use an explicit CASE with ::boolean casts in the critical enable
expression so the result type is always boolean.
- Make GreatestExpr emit safe casts on Postgres.
- Add a one-time normalization step in MigrationRequirements (runs on
startup + xray restarts) that forces the relevant enable/enabled
columns to boolean on Postgres using an idempotent DO block + USING
cast. This cleans up pre-existing skew without a full re-migration.
This branch is based on upstream/main (original mhsanaei/3x-ui main).
The node traffic sync now survives arbitrary public-API inbound
updates on PostgreSQL.