Skip to content

2251 - Resolve server deactivation error for servers with email teams#2253

Merged
crivetimihai merged 1 commit intomainfrom
2251-deactivate-virtual-server
Jan 21, 2026
Merged

2251 - Resolve server deactivation error for servers with email teams#2253
crivetimihai merged 1 commit intomainfrom
2251-deactivate-virtual-server

Conversation

@gcgoncalves
Copy link
Copy Markdown
Collaborator

@gcgoncalves gcgoncalves commented Jan 20, 2026

🐛 Bug-fix PR

📌 Summary

This PR fixes a critical bug that prevented the deactivation of a virtual server when it was associated with an email notification team. The action would fail due to a database error, making it impossible to disable certain servers through the Admin UI or API. This fix ensures the deactivation process is robust and reliable, regardless of the server's associations

Closes #2251

🔁 Reproduction Steps

  1. Create a virtual server.
  2. Create an email notification team and associate it with the server.
  3. Navigate to the Admin UI and attempt to deactivate the server.
  4. Observe the operation fails with an internal server error.

🐞 Root Cause

The root cause of the issue was a psycopg.errors.FeatureNotSupported error from PostgreSQL, stating: "FOR UPDATE cannot be applied to the nullable side of an outer join".

This occurred because the set_server_state service method used SQLAlchemy's joinedload strategy to fetch the server along with its related email_team. This created a LEFT OUTER JOIN in the SQL query. When the database
transaction attempted to lock the server row for the update using FOR UPDATE, it conflicted with the outer join, as PostgreSQL does not support locking on the nullable side of such joins.

💡 Fix Description

The fix replaces the data loading strategy for the email_team relationship within ServerService. The joinedload has been replaced with selectinload.

selectinload resolves the problem by issuing a separate SELECT statement to load the related email_team after the server has been retrieved. This decouples the queries, avoiding the problematic LEFT OUTER JOIN in the initial
SELECT ... FOR UPDATE statement and allowing the row lock to be acquired without error.

In addition to the core fix, this PR introduces comprehensive unit tests for the set_server_state method and the corresponding admin API endpoint. These tests cover activation, deactivation, permission handling, and
specifically verify that the fix works correctly when an email team is present, preventing future regressions.

🧪 Verification

Check Command Status
Lint suite make lint
Unit tests make test
Coverage ≥ 90 % make coverage
Manual regression no longer fails steps / screenshots

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • No secrets/credentials committed

@gcgoncalves gcgoncalves force-pushed the 2251-deactivate-virtual-server branch from 385e97e to 6a2e276 Compare January 20, 2026 16:53
@gcgoncalves gcgoncalves marked this pull request as ready for review January 20, 2026 18:20
This commit fixes a bug where deactivating a virtual server associated with an email notification team would fail with a database error.

The root cause was the use of `joinedload` to fetch the `email_team` relationship when retrieving the server to be updated. This resulted in a `LEFT OUTER JOIN` in the underlying SQL query. When the query also included a
`FOR UPDATE` clause to lock the server row, PostgreSQL raised a `FeatureNotSupported` error because it cannot apply a lock to the nullable side of an outer join.

This fix changes the SQLAlchemy loading strategy from `joinedload` to `selectinload` for the `DbServer.email_team` relationship within the `set_server_state` method. `selectinload` resolves the issue by loading the relate
`email_team` in a separate `SELECT` statement, thus avoiding the problematic `JOIN` in the initial `SELECT ... FOR UPDATE` query.

Additionally, comprehensive unit tests have been added for both the `ServerService` and the admin panel routes to cover server activation, deactivation, and to verify that the fix works as expected, preventing future
regressions.

Signed-off-by: Gabriel Costa <gabrielcg@proton.me>
@crivetimihai crivetimihai force-pushed the 2251-deactivate-virtual-server branch from 6a2e276 to 708e24e Compare January 21, 2026 09:26
@crivetimihai crivetimihai merged commit 591644d into main Jan 21, 2026
51 checks passed
@crivetimihai crivetimihai deleted the 2251-deactivate-virtual-server branch January 21, 2026 10:42
010gvr pushed a commit to 010gvr/mcp-context-forge that referenced this pull request Jan 23, 2026
…IBM#2253)

This commit fixes a bug where deactivating a virtual server associated with an email notification team would fail with a database error.

The root cause was the use of `joinedload` to fetch the `email_team` relationship when retrieving the server to be updated. This resulted in a `LEFT OUTER JOIN` in the underlying SQL query. When the query also included a
`FOR UPDATE` clause to lock the server row, PostgreSQL raised a `FeatureNotSupported` error because it cannot apply a lock to the nullable side of an outer join.

This fix changes the SQLAlchemy loading strategy from `joinedload` to `selectinload` for the `DbServer.email_team` relationship within the `set_server_state` method. `selectinload` resolves the issue by loading the relate
`email_team` in a separate `SELECT` statement, thus avoiding the problematic `JOIN` in the initial `SELECT ... FOR UPDATE` query.

Additionally, comprehensive unit tests have been added for both the `ServerService` and the admin panel routes to cover server activation, deactivation, and to verify that the fix works as expected, preventing future
regressions.

Signed-off-by: Gabriel Costa <gabrielcg@proton.me>
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
…IBM#2253)

This commit fixes a bug where deactivating a virtual server associated with an email notification team would fail with a database error.

The root cause was the use of `joinedload` to fetch the `email_team` relationship when retrieving the server to be updated. This resulted in a `LEFT OUTER JOIN` in the underlying SQL query. When the query also included a
`FOR UPDATE` clause to lock the server row, PostgreSQL raised a `FeatureNotSupported` error because it cannot apply a lock to the nullable side of an outer join.

This fix changes the SQLAlchemy loading strategy from `joinedload` to `selectinload` for the `DbServer.email_team` relationship within the `set_server_state` method. `selectinload` resolves the issue by loading the relate
`email_team` in a separate `SELECT` statement, thus avoiding the problematic `JOIN` in the initial `SELECT ... FOR UPDATE` query.

Additionally, comprehensive unit tests have been added for both the `ServerService` and the admin panel routes to cover server activation, deactivation, and to verify that the fix works as expected, preventing future
regressions.

Signed-off-by: Gabriel Costa <gabrielcg@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][UI]: Cannot deactivate virtual server

2 participants