We have a Spring Boot application, written in Kotlin, which runs in a container on Digital Ocean App Platform.
Versions:
- MySQL 8.0.30
- Kotlin 2.0.20
- Spring Boot 3.4.2
- HikariCP 3.4.5
- MySQL Connector/J 9.1.0
At, seemingly random, times, we're getting errors from our select queries that indicate that the result set was "Not a navigable ResultSet".
2025-02-18T14:37:44.866 [join-backend-v3-prod-85f5d9c488-scsgt] [http-nio-0.0.0.0-8080-exec-5] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - [] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [select
u.uid,
first_name,
last_name,
email,
ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
locale,
time_zone,
is_admin,
exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
from users u
left join subscription_summaries ss on u.uid = ss.uid
where u.uid = ?
and auth_token = ?]; Not a navigable ResultSet.
at .springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:124)
at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
at .springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1556)
at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:677)
at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:178)
at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:186)
at cc.join.backend.repositories.SpringUserRepository.fetchPrincipalByIdAndAuthToken(SpringUserRepository.kt:38)
at cc.join.backend.spring.JoinAuthenticationProvider.retrieveUser(JoinAuthenticationProvider.kt:28)
at .springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:133)
at .springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
at cc.join.backend.spring.JoinAuthenticationTokenFilter.doFilterInternal(JoinAuthenticationTokenFilter.kt:56)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at cc.join.backend.spring.JoinInternalJwtFilter.doFilterInternal(JoinInternalJwtFilter.kt:59)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at cc.join.backend.spring.ActuatorApiKeyFilter.doFilterInternal(ActuatorApiKeyFilter.kt:41)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at .springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
at .springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
at .springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:243)
at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
at .springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
at .springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:238)
at .springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
at .springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .zalando.logbook.servlet.LogbookFilter.doFilter(LogbookFilter.java:76)
at .zalando.logbook.servlet.SecureLogbookFilter.doFilter(SecureLogbookFilter.java:32)
at .zalando.logbook.servlet.HttpFilter.doFilter(HttpFilter.java:32)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:114)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at .apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at .apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at .apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at .apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at .apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at .apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:731)
at .apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at .apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
at .apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at .apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
at .apache.tomcat.util.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at .apache.tomcat.util.SocketProcessorBase.run(SocketProcessorBase.java:52)
at .apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at .apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at .apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: Not a navigable ResultSet.
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:121)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:81)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:55)
at com.mysql.cj.jdbc.result.ResultSetImpl.next(ResultSetImpl.java:1807)
at com.zaxxer.hikari.pool.HikariProxyResultSet.next(HikariProxyResultSet.java)
at cc.join.backend.repositories.SpringUserRepository.joinPrincipalResultSetExtractor$lambda$3(SpringUserRepository.kt:64)
at .springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
... 99 common frames omitted
The code that executes the query is:
import java.time.DateTimeException
import java.time.ZoneId
import java.time.zone.ZoneRulesException
import java.util.Locale
import javax.sql.DataSource
@Repository
class SpringUserRepository(dataSource: DataSource) {
private val jdbcTemplate = NamedParameterJdbcTemplate(dataSource)
/** Fetch a user with the given userId and token exists in the database. If no user with
* the provided [userId] and [token] is found, returns null. */
fun fetchPrincipalByIdAndAuthToken(userId: Long, token: String): JoinPrincipal? {
val sql = """
select
u.uid,
first_name,
last_name,
email,
ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
locale,
time_zone,
is_admin,
exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
from users u
left join subscription_summaries ss on u.uid = ss.uid
where u.uid = :uid
and auth_token = :authToken
""".trimIndent()
return jdbcTemplate.query(sql, mapOf("uid" to userId, "authToken" to token), joinPrincipalResultSetExtractor)
}
private val joinPrincipalResultSetExtractor: ResultSetExtractor<JoinPrincipal> = ResultSetExtractor { resultSet ->
if (resultSet.next()) {
val isBlacklisted = resultSet.getBoolean("is_blacklisted")
val timeZone: ZoneId = resultSet.getString("time_zone")
?.takeIf { it.isNotBlank() }
?.let {
try {
ZoneId.of(it)
} catch (zoneRulesException: ZoneRulesException) {
null
} catch (dateTimeException: DateTimeException) {
null
}
}
?: StaticSettings.DEFAULT_ZONE_ID
JoinPrincipal(
id = resultSet.getLong("uid"),
firstName = resultSet.getString("first_name"),
locale = Locale.of(resultSet.getString("locale").ifEmpty { "en" }),
timeZone = timeZone,
isSubscriptionActive = !isBlacklisted && resultSet.getBoolean("subscription_active"),
isAdmin = resultSet.getBoolean("is_admin"),
isBlacklisted = isBlacklisted,
)
} else {
null
}
}
}
This query could result in zero rows returned, but, as it's a select query, ResultSet.next()
should still work, returning false.
We see the same thing with other queries that potentially return 0 rows.
Datasource configuration:
spring.datasource:
# Our database contains zero dates and datetimes unfortunately, so we have the JDBC driver convert these to NULLs.
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:join}?zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&serverTimezone=UTC&auto
username: ${DB_USER}
password: ${DB_PASSWORD}
hikari:
data-source-properties:
# The MySQL JDBC driver does not set a socket timeout by default. When the connection to the database gets
# severed without a normal TCP shutdown, this can result in database connections and not being available
# for the application.
# See for more information.
socketTimeout: 30000
# See for documentation about the following properties:
# Maximum amount of time that a connection will be tested for aliveness. This value must be less than the
# connection-timeout.
validation-timeout: 4_000
# when creating a new database connection, fail after 5 seconds when no connection can be established. If it
# takes longer than this, chances are that high that it will be impossible to get a connection.
connection-timeout: 5_000
# Regularly check database connections for aliveness. This prevents database code from being handed a connection
# that has been severed.
keepalive-time: 60_000
# maximum nr of connections. We're not setting 'minimum-idle', so this will be a fixed-size pool.
maximum-pool-size: 25
# Whenever a connection is not returned to the pool within 10 seconds, mark it as having been leaked. = 10_000
leak-detection-threshold: 10_000
The weird thing is that most of the time, things work perfectly. It seems rather random, and what does not help is that we cannot find any similar issues on Google nor this site.
Because we had seen the same error on our development environment, we have tried to trigger the error by performing a load test on the development environment. Unfortunately, this did not trigger the error.
We're in contact with Digital Ocean support. They indicate not having seen any database or network errors around the times that the problem occurred.
We have a Spring Boot application, written in Kotlin, which runs in a container on Digital Ocean App Platform.
Versions:
- MySQL 8.0.30
- Kotlin 2.0.20
- Spring Boot 3.4.2
- HikariCP 3.4.5
- MySQL Connector/J 9.1.0
At, seemingly random, times, we're getting errors from our select queries that indicate that the result set was "Not a navigable ResultSet".
2025-02-18T14:37:44.866 [join-backend-v3-prod-85f5d9c488-scsgt] [http-nio-0.0.0.0-8080-exec-5] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - [] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [select
u.uid,
first_name,
last_name,
email,
ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
locale,
time_zone,
is_admin,
exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
from users u
left join subscription_summaries ss on u.uid = ss.uid
where u.uid = ?
and auth_token = ?]; Not a navigable ResultSet.
at .springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:124)
at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
at .springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1556)
at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:677)
at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:178)
at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:186)
at cc.join.backend.repositories.SpringUserRepository.fetchPrincipalByIdAndAuthToken(SpringUserRepository.kt:38)
at cc.join.backend.spring.JoinAuthenticationProvider.retrieveUser(JoinAuthenticationProvider.kt:28)
at .springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:133)
at .springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
at cc.join.backend.spring.JoinAuthenticationTokenFilter.doFilterInternal(JoinAuthenticationTokenFilter.kt:56)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at cc.join.backend.spring.JoinInternalJwtFilter.doFilterInternal(JoinInternalJwtFilter.kt:59)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at cc.join.backend.spring.ActuatorApiKeyFilter.doFilterInternal(ActuatorApiKeyFilter.kt:41)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at .springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
at .springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
at .springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
at .springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
at .springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:243)
at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
at .springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
at .springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:238)
at .springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
at .springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .zalando.logbook.servlet.LogbookFilter.doFilter(LogbookFilter.java:76)
at .zalando.logbook.servlet.SecureLogbookFilter.doFilter(SecureLogbookFilter.java:32)
at .zalando.logbook.servlet.HttpFilter.doFilter(HttpFilter.java:32)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:114)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at .apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at .apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at .apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at .apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at .apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at .apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:731)
at .apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at .apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
at .apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at .apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
at .apache.tomcat.util.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at .apache.tomcat.util.SocketProcessorBase.run(SocketProcessorBase.java:52)
at .apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at .apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at .apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: Not a navigable ResultSet.
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:121)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:81)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:55)
at com.mysql.cj.jdbc.result.ResultSetImpl.next(ResultSetImpl.java:1807)
at com.zaxxer.hikari.pool.HikariProxyResultSet.next(HikariProxyResultSet.java)
at cc.join.backend.repositories.SpringUserRepository.joinPrincipalResultSetExtractor$lambda$3(SpringUserRepository.kt:64)
at .springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
... 99 common frames omitted
The code that executes the query is:
import java.time.DateTimeException
import java.time.ZoneId
import java.time.zone.ZoneRulesException
import java.util.Locale
import javax.sql.DataSource
@Repository
class SpringUserRepository(dataSource: DataSource) {
private val jdbcTemplate = NamedParameterJdbcTemplate(dataSource)
/** Fetch a user with the given userId and token exists in the database. If no user with
* the provided [userId] and [token] is found, returns null. */
fun fetchPrincipalByIdAndAuthToken(userId: Long, token: String): JoinPrincipal? {
val sql = """
select
u.uid,
first_name,
last_name,
email,
ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
locale,
time_zone,
is_admin,
exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
from users u
left join subscription_summaries ss on u.uid = ss.uid
where u.uid = :uid
and auth_token = :authToken
""".trimIndent()
return jdbcTemplate.query(sql, mapOf("uid" to userId, "authToken" to token), joinPrincipalResultSetExtractor)
}
private val joinPrincipalResultSetExtractor: ResultSetExtractor<JoinPrincipal> = ResultSetExtractor { resultSet ->
if (resultSet.next()) {
val isBlacklisted = resultSet.getBoolean("is_blacklisted")
val timeZone: ZoneId = resultSet.getString("time_zone")
?.takeIf { it.isNotBlank() }
?.let {
try {
ZoneId.of(it)
} catch (zoneRulesException: ZoneRulesException) {
null
} catch (dateTimeException: DateTimeException) {
null
}
}
?: StaticSettings.DEFAULT_ZONE_ID
JoinPrincipal(
id = resultSet.getLong("uid"),
firstName = resultSet.getString("first_name"),
locale = Locale.of(resultSet.getString("locale").ifEmpty { "en" }),
timeZone = timeZone,
isSubscriptionActive = !isBlacklisted && resultSet.getBoolean("subscription_active"),
isAdmin = resultSet.getBoolean("is_admin"),
isBlacklisted = isBlacklisted,
)
} else {
null
}
}
}
This query could result in zero rows returned, but, as it's a select query, ResultSet.next()
should still work, returning false.
We see the same thing with other queries that potentially return 0 rows.
Datasource configuration:
spring.datasource:
# Our database contains zero dates and datetimes unfortunately, so we have the JDBC driver convert these to NULLs.
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:join}?zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&serverTimezone=UTC&auto
username: ${DB_USER}
password: ${DB_PASSWORD}
hikari:
data-source-properties:
# The MySQL JDBC driver does not set a socket timeout by default. When the connection to the database gets
# severed without a normal TCP shutdown, this can result in database connections and not being available
# for the application.
# See https://github/brettwooldridge/HikariCP/wiki/Rapid-Recover for more information.
socketTimeout: 30000
# See https://github/brettwooldridge/HikariCP for documentation about the following properties:
# Maximum amount of time that a connection will be tested for aliveness. This value must be less than the
# connection-timeout.
validation-timeout: 4_000
# when creating a new database connection, fail after 5 seconds when no connection can be established. If it
# takes longer than this, chances are that high that it will be impossible to get a connection.
connection-timeout: 5_000
# Regularly check database connections for aliveness. This prevents database code from being handed a connection
# that has been severed.
keepalive-time: 60_000
# maximum nr of connections. We're not setting 'minimum-idle', so this will be a fixed-size pool.
maximum-pool-size: 25
# Whenever a connection is not returned to the pool within 10 seconds, mark it as having been leaked. = 10_000
leak-detection-threshold: 10_000
The weird thing is that most of the time, things work perfectly. It seems rather random, and what does not help is that we cannot find any similar issues on Google nor this site.
Because we had seen the same error on our development environment, we have tried to trigger the error by performing a load test on the development environment. Unfortunately, this did not trigger the error.
We're in contact with Digital Ocean support. They indicate not having seen any database or network errors around the times that the problem occurred.
Share Improve this question edited 12 hours ago Ilja Booij asked 14 hours ago Ilja BooijIlja Booij 11 bronze badge New contributor Ilja Booij is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 5 |1 Answer
Reset to default 0Some databases only allow forward scrolling ResultSet
.
Perhaps setting TYPE_SCROLL_INSENSITIVE
can solve it:
Statement stmt = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, // Makes ResultSet scrollable
ResultSet.CONCUR_READ_ONLY // Read-only mode
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
Odd that it's intermittent, I agree.
application.yaml
– Ilja Booij Commented 12 hours ago