[GH-ISSUE #3300] POST /resource/{resourceId} returns sso: null even though the value is persisted correctly #35782

Open
opened 2026-06-18 21:00:43 -05:00 by GiteaMirror · 0 comments
Owner

Originally created by @fperk on GitHub (Jun 17, 2026).
Original GitHub issue: https://github.com/fosrl/pangolin/issues/3300

Describe the Bug

Description

Calling the resource update endpoint with sso: true returns HTTP 200,
but the response body contains "sso": null instead of the value that
was just written. A subsequent GET on the same resource correctly
shows sso: true, confirming the write itself succeeded — only the
update endpoint's response is wrong.

Impact

This breaks API consumers that rely on the mutation response to
reflect the new state (rather than re-fetching), since null is
indistinguishable from "field not set." In our case it surfaced as a
Terraform provider plan-consistency error (provider sets state from
the POST response, getting false after coercing null for a
non-nullable field, while the plan expected true).

Environment

  • OS Type & Version: Ubuntu 24.04 + docker compose
  • Pangolin Version: 1.19.2
  • Edition (Community or Enterprise): Enterprise
  • Gerbil Version: 1.4.2
  • Traefik Version: 3.7.5

To Reproduce

  1. POST /resource/{resourceId} with body:
curl -X 'POST' \
  'https://api.pangolin.net/v1/resource/{resourceId}' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer XXXXX' \
  -H 'Content-Type: application/json' \
  -d '{
  "sso": true
}'
  1. Observe the response: HTTP 200, but data.sso is null.
{
  "data": {
    "resourceId": 12,
    "resourcePolicyId": null,
    "defaultResourcePolicyId": 12,
    "resourceGuid": "XXXX",
    "orgId": "XXXX",
    "niceId": "XXXX",
    "name": "XXXX",
    "subdomain": "XXXX",
    "fullDomain": "XXXX",
    "domainId": "XXXX",
    "ssl": true,
    "blockAccess": false,
    "proxyPort": null,
    "sso": null,
    "emailWhitelistEnabled": null,
    "applyRules": null,
    "enabled": true,
    "stickySession": false,
    "tlsServerName": null,
    "setHostHeader": null,
    "enableProxy": true,
    "skipToIdpId": null,
    "headers": null,
    "proxyProtocol": false,
    "proxyProtocolVersion": 1,
    "maintenanceModeEnabled": false,
    "maintenanceModeType": "forced",
    "maintenanceTitle": null,
    "maintenanceMessage": null,
    "maintenanceEstimatedTime": null,
    "postAuthPath": null,
    "health": "unknown",
    "wildcard": false,
    "mode": "http",
    "pamMode": "passthrough",
    "authDaemonMode": "site",
    "authDaemonPort": 22123
  },
  "success": true,
  "error": false,
  "message": "HTTP resource updated successfully",
  "status": 200
}
  1. Immediately call GET /resource/{resourceId}.
  2. Observe data.sso is correctly true.
{
  "data": {
    "resourceId": 12,
    "resourcePolicyId": null,
    "defaultResourcePolicyId": 12,
    "resourceGuid": "XXXX",
    "orgId": "XXXX",
    "niceId": "XXXX",
    "name": "XXXX",
    "subdomain": "XXXX",
    "fullDomain": "XXXX",
    "domainId": "XXXX",
    "ssl": true,
    "blockAccess": false,
    "proxyPort": null,
    "sso": true,
    "emailWhitelistEnabled": null,
    "applyRules": null,
    "enabled": true,
    "stickySession": false,
    "tlsServerName": null,
    "setHostHeader": null,
    "enableProxy": true,
    "skipToIdpId": null,
    "headers": null,
    "proxyProtocol": false,
    "proxyProtocolVersion": 1,
    "maintenanceModeEnabled": false,
    "maintenanceModeType": "forced",
    "maintenanceTitle": null,
    "maintenanceMessage": null,
    "maintenanceEstimatedTime": null,
    "postAuthPath": null,
    "health": "unknown",
    "wildcard": false,
    "mode": "http",
    "pamMode": "passthrough",
    "authDaemonMode": "site",
    "authDaemonPort": 22123
  },
  "success": true,
  "error": false,
  "message": "Resource retrieved successfully",
  "status": 200
}

Expected Behavior

The POST response should reflect the same persisted state that GET
returns — i.e. sso: true in step 2.

Originally created by @fperk on GitHub (Jun 17, 2026). Original GitHub issue: https://github.com/fosrl/pangolin/issues/3300 ### Describe the Bug ## Description Calling the resource update endpoint with `sso: true` returns HTTP 200, but the response body contains `"sso": null` instead of the value that was just written. A subsequent GET on the same resource correctly shows `sso: true`, confirming the write itself succeeded — only the update endpoint's response is wrong. ## Impact This breaks API consumers that rely on the mutation response to reflect the new state (rather than re-fetching), since `null` is indistinguishable from "field not set." In our case it surfaced as a Terraform provider plan-consistency error (provider sets state from the POST response, getting `false` after coercing `null` for a non-nullable field, while the plan expected `true`). ### Environment - OS Type & Version: Ubuntu 24.04 + docker compose - Pangolin Version: 1.19.2 - Edition (Community or Enterprise): Enterprise - Gerbil Version: 1.4.2 - Traefik Version: 3.7.5 ### To Reproduce 1. `POST /resource/{resourceId}` with body: ```bash curl -X 'POST' \ 'https://api.pangolin.net/v1/resource/{resourceId}' \ -H 'accept: application/json' \ -H 'Authorization: Bearer XXXXX' \ -H 'Content-Type: application/json' \ -d '{ "sso": true }' ``` 2. Observe the response: HTTP 200, but `data.sso` is `null`. ```json { "data": { "resourceId": 12, "resourcePolicyId": null, "defaultResourcePolicyId": 12, "resourceGuid": "XXXX", "orgId": "XXXX", "niceId": "XXXX", "name": "XXXX", "subdomain": "XXXX", "fullDomain": "XXXX", "domainId": "XXXX", "ssl": true, "blockAccess": false, "proxyPort": null, "sso": null, "emailWhitelistEnabled": null, "applyRules": null, "enabled": true, "stickySession": false, "tlsServerName": null, "setHostHeader": null, "enableProxy": true, "skipToIdpId": null, "headers": null, "proxyProtocol": false, "proxyProtocolVersion": 1, "maintenanceModeEnabled": false, "maintenanceModeType": "forced", "maintenanceTitle": null, "maintenanceMessage": null, "maintenanceEstimatedTime": null, "postAuthPath": null, "health": "unknown", "wildcard": false, "mode": "http", "pamMode": "passthrough", "authDaemonMode": "site", "authDaemonPort": 22123 }, "success": true, "error": false, "message": "HTTP resource updated successfully", "status": 200 } ``` 3. Immediately call `GET /resource/{resourceId}`. 4. Observe `data.sso` is correctly `true`. ```json { "data": { "resourceId": 12, "resourcePolicyId": null, "defaultResourcePolicyId": 12, "resourceGuid": "XXXX", "orgId": "XXXX", "niceId": "XXXX", "name": "XXXX", "subdomain": "XXXX", "fullDomain": "XXXX", "domainId": "XXXX", "ssl": true, "blockAccess": false, "proxyPort": null, "sso": true, "emailWhitelistEnabled": null, "applyRules": null, "enabled": true, "stickySession": false, "tlsServerName": null, "setHostHeader": null, "enableProxy": true, "skipToIdpId": null, "headers": null, "proxyProtocol": false, "proxyProtocolVersion": 1, "maintenanceModeEnabled": false, "maintenanceModeType": "forced", "maintenanceTitle": null, "maintenanceMessage": null, "maintenanceEstimatedTime": null, "postAuthPath": null, "health": "unknown", "wildcard": false, "mode": "http", "pamMode": "passthrough", "authDaemonMode": "site", "authDaemonPort": 22123 }, "success": true, "error": false, "message": "Resource retrieved successfully", "status": 200 } ``` ### Expected Behavior The POST response should reflect the same persisted state that GET returns — i.e. `sso: true` in step 2.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/pangolin#35782