Repository navigation
Spring Cloud /actuator/refresh corrupts live SentryOptions #6369
Description
Integration
sentry-spring-boot-4
Java Version
JVM 21 (OpenJ9)
Other Error Monitoring Solution
No
Other Error Monitoring Solution Name
No response
Version
8.61.1
Steps to Reproduce
Environment
- io.sentry:sentry-spring-boot-4-starter 8.61.1 (sentry + sentry-spring-7 + sentry-logback 8.61.1)
- Spring Boot 4.1.2, Spring Cloud 2025.1.x (config client + refresh endpoint enabled)
Summary
SentryProperties extends SentryOptions, and
SentryAutoConfiguration$HubConfiguration.sentryHub passes the bound
@ConfigurationProperties bean itself to Sentry.init(options). The bean
therefore is the live SentryOptions held by the initialized scopes.
When Spring Cloud's /actuator/refresh fires EnvironmentChangeEvent,
ConfigurationPropertiesRebinder rebinds all @ConfigurationProperties
beans — including SentryProperties. Because the bean is the live options
object, the rebind corrupts the running SDK:
Repro
- Spring Boot 4 app with
sentry-spring-boot-4-starter, Spring Cloud Config
client,management.endpoints.web.exposure.includecoveringrefresh. - Configure
sentry.dsn,sentry.environment,sentry.servernamevia a
remote property source (spring-cloud-config). - Start → events arrive with correct
environment/server_name. POST /actuator/refresh(even with no config change).- Subsequent events carry
environment: production,
server_name: <hostname>— and the refresh request itself throws the
retrieveParsedDsnNPE.
Expected Result
sentry.* should be resilient to configuration rebinding. Either:
sentryHubcopies the bound values into a freshSentryOptionsbefore
Sentry.init— the live options then stay immutable after init, and a
refresh simply doesn't apply new values (no corruption), or- the autoconfiguration listens for
EnvironmentChangeEvent/
RefreshScopeRefreshedEventand performs a properSentry.initwith a
fully-boundSentryProperties— making refresh actually work.
Actual Result
After POST /actuator/refresh — reproducible even with no config change:
-
The request handling
/actuator/refreshitself crashes during
SentryTracer.finish— the liveSentryOptions.dsnis transiently
nullwhileConfigurationPropertiesRebinderrebinds the
SentryPropertiesbean:java.lang.NullPointerException / IllegalArgumentException at io.sentry.util.Objects.requireNonNull(Objects.java:13) at io.sentry.Dsn.<init>(Dsn.java:54) at io.sentry.SentryOptions.lambda$new$0(SentryOptions.java:113) at io.sentry.util.LazyEvaluator.getValue(LazyEvaluator.java:39) at io.sentry.SentryOptions.retrieveParsedDsn(SentryOptions.java:831) at io.sentry.Baggage.setValuesFromTransaction(Baggage.java:529) at io.sentry.SentryTracer.finish(SentryTracer.java:292) at io.sentry.spring7.tracing.SentryTracingFilter.doFilterWithTransaction(SentryTracingFilter.java:172) -
dsnrecovers after rebind, so telemetry keeps flowing to the correct
project — butenvironmentandserverNamestaynullon the live
options. All subsequent events are emitted withenvironment = null
(Sentry server assigns the defaultproduction) andserver_name = <container hostname>(auto-detection fallback) — while
/actuator/configpropsstill showssentry.environment/sentry.servername
correctly bound on the (new)SentryPropertiesbean. -
Only a JVM restart restores correct
environment/server_name.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsWaiting for: Product Owner
Activity
linear-code commentedon Oct 23, 2026
JAVA-798