You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
findByPrincipalName does not correctly return sessions #3452
Describe the bug
If you call findByPrincipalName you can get inconstant results, as query listSessionsByPrincipalNameQuery used below does not order results by id. Later, extractor of the result is trying to combine results for the same sessions – but it's calling getLast on list that it's creating, so if results are not ordered, then result list of extractor might have multiple entries for same session. The problem is that later this list is converted to map by id – at this point we will loose some attributes.
To Reproduce
Have two sessions for the same principle name with multiple attributes. Call findByPrincipalName.
Expected behavior
Result should be ordered or extractor should not call getLast but actually look by an id. Also, extractor could return a Set in that case.
Reproduced with spring-session-jdbc 4.1.1 and PostgreSQL 18.2. The unordered query and adjacency-based extractor are also present on main at b61972a, checked on 2026-10-06.
A repository-level regression test reproduces the missing attributes without concurrent requests:
Create and save 120 sessions for the same principal. Each has the principal-name index attribute and three string attributes, first, second, and third, each containing "x".repeat(1200).
Load every third session with findById, add later = "x", and save it again. This inserts the new attribute separately from the original rows.
Run ANALYZE spring_session, spring_session_attributes.
Call findByPrincipalName and check that every returned session still contains first, second, and third.
With the unordered query, all 120 session IDs are returned, but exactly 40 sessions have only ["later"] as their attribute names. The assertion fails with:
but could not find the following element(s):
["first", "second", "third"]
Adding only ORDER BY S.PRIMARY_ID makes the same test pass. The test runs against a real PostgreSQL container: SessionStoreIT.java. The comparison removed only that ORDER BY line from the custom query.
The failure matches the explanation in this issue. The extractor reuses only the last session object. If a session's rows appear again after another session's rows, it creates a new partial object, and the final map entry replaces the earlier object. PostgreSQL does not guarantee row order without ORDER BY. A separate SQL reproduction using the session schema produced a Hash Right Join with a sequential scan of the attribute table, so the rows need not arrive grouped by session.
For a logged-in device list, this can produce missing device names or omitted devices when the lifetime attribute is missing. In this reproduction, operations using only the returned session IDs would still have all 120 IDs available.
This customizer works around the issue using the existing query plus the ordering:
@BeanSessionRepositoryCustomizer<JdbcIndexedSessionRepository> sessionsListedInOrder() {
returnrepository -> repository.setListSessionsByPrincipalNameQuery(""" SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES FROM %TABLE_NAME% S LEFT JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID WHERE S.PRINCIPAL_NAME = ? ORDER BY S.PRIMARY_ID """);
}
The types are org.springframework.session.config.SessionRepositoryCustomizer and org.springframework.session.jdbc.JdbcIndexedSessionRepository. An upstream fix could add this ordering to the default query, or make the extractor collect attributes by session ID regardless of row order.
Activity
MrEx3cut0r commentedon Aug 8, 2025
Hi, anyone already works on it?
AlexanderReaper7 commentedon Oct 6, 2026
Reproduced with
spring-session-jdbc4.1.1 and PostgreSQL 18.2. The unordered query and adjacency-based extractor are also present onmainat b61972a, checked on 2026-10-06.A repository-level regression test reproduces the missing attributes without concurrent requests:
first,second, andthird, each containing"x".repeat(1200).findById, addlater = "x", and save it again. This inserts the new attribute separately from the original rows.ANALYZE spring_session, spring_session_attributes.findByPrincipalNameand check that every returned session still containsfirst,second, andthird.With the unordered query, all 120 session IDs are returned, but exactly 40 sessions have only
["later"]as their attribute names. The assertion fails with:Adding only
ORDER BY S.PRIMARY_IDmakes the same test pass. The test runs against a real PostgreSQL container: SessionStoreIT.java. The comparison removed only thatORDER BYline from the custom query.The failure matches the explanation in this issue. The extractor reuses only the last session object. If a session's rows appear again after another session's rows, it creates a new partial object, and the final map entry replaces the earlier object. PostgreSQL does not guarantee row order without
ORDER BY. A separate SQL reproduction using the session schema produced aHash Right Joinwith a sequential scan of the attribute table, so the rows need not arrive grouped by session.For a logged-in device list, this can produce missing device names or omitted devices when the lifetime attribute is missing. In this reproduction, operations using only the returned session IDs would still have all 120 IDs available.
This customizer works around the issue using the existing query plus the ordering:
The types are
org.springframework.session.config.SessionRepositoryCustomizerandorg.springframework.session.jdbc.JdbcIndexedSessionRepository. An upstream fix could add this ordering to the default query, or make the extractor collect attributes by session ID regardless of row order.Order JDBC principal session rows by primary key