Skip to content

Update v9 branch - #6530

Merged
runningcode merged 43 commits into
9.x.xfrom
sync/main-to-9.x.x-2026-11-10
Nov 10, 2026
Merged

runningcode merged 43 commits into
9.x.xfrom
sync/main-to-9.x.x-2026-11-10

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

Weekly sync of main (f3a3bc41f) into 9.x.x. It brings in 42 commits, with the merge conflicts resolved. This replaces #6529, which used main as its head branch, so its conflicts couldn't be fixed in place.

Please merge with a merge commit (not squashed).

Note

No v8 release has shipped since 8.63.0, so all 42 commits are v8 changes that haven't been released yet. The last sync (#6474) stopped at the 8.63.0 release on purpose, so a 9.x alpha wouldn't ship them early. This PR brings in everything on main, as the weekly sync asked.

Conflict resolution

  • Module build.gradle.kts files (async-profiler, graphql, graphql-22, graphql-core, jcache, jdbc, jul, kafka, launchdarkly-server, log4j2, logback, openfeature, openfeign, opentelemetry-agentless, opentelemetry-agentless-spring, quartz, servlet, servlet-jakarta, spring, spring-boot): kept the io.sentry.spotless, io.sentry.jdk-target and io.sentry.publish convention plugins from main. Dropped io.sentry.animalsniffer, because 9.x.x removed the JVM animal-sniffer plugin.
  • sentry-apache-http-client-5/build.gradle.kts: deleted. 9.x.x removed the module, and main only added the convention plugins to it.
  • gradle/libs.versions.toml: kept main's bump of gummyBears to 0.16.0. Left out java8Signature, which 9.x.x removed.
  • R8 override from feat(android): Raise minSdk from 21 to 24 #6518 (build.gradle.kts, buildSrc/.../Config.kt): main dropped Config.BuildPlugins/Config.AGP and the AGP buildscript classpath, and now applies VERSION_AGP in each build's settings. The R8 workaround is now an r8 entry in the version catalog (9.4.14). The buildscripts of the root build, sentry-android-integration-tests and sentry-samples-android put it on the classpath only when VERSION_AGP is set. The integration-tests build needs it because the AGP matrix runs assembleUiTests, which minifies, in that build.
  • SpanFrameMetricsCollector.java: used 9.x.x's enabled = options.isEnableFramesTracking(), because enablePerformanceV2 is gone. Kept main's early frameMetricsCollector.prepare() call (fix(android): Don't block the main thread on the frame metrics looper #6500).
  • SentryJobListener.java: kept the java.util imports that main's monitor-config code needs. Dropped the ApiStatus import, because 9.x.x removed @ApiStatus.Experimental.
  • sentry-samples-android/build.gradle.kts: kept main's published-coordinate dependencies and added io.sentry:sentry-android-ndk, because sentry-android no longer includes it on 9.x.x (feat(android): Drop sentry-android-ndk from sentry-android #6436).
  • CHANGELOG.md: kept main's 9.0.0 warning banner. Merged the two ## Unreleased sections: 9.x.x's Breaking Changes, Improvements and Internal, main's Features, Behavioral Changes and Dependencies, and both sides' Fixes. In ## 8.63.0, kept main's Internal entry and the entries that 9.x.x already had there.

Verified locally

  • compileJava compileKotlin compileTestJava compileTestKotlin for all JVM modules
  • compileReleaseUnitTestKotlin compileReleaseUnitTestJavaWithJavac for all Android modules
  • checkKotlinAbi and spotlessCheck
  • :sentry-quartz:test and SpanFrameMetricsCollector unit tests
  • VERSION_AGP=9.2.1 buildEnvironment for the root and integration-tests builds: com.android.tools:r8:9.4.14 is on the buildscript classpath

The AGP matrix in CI will check the R8 override end to end.

#skip-changelog

via no.

--

View Session [Sentry]

runningcode and others added 30 commits November 5, 2026 17:29
* docs: Announce Java 11 and minSdk 26 requirements for SDK 9

Add a warning at the top of the changelog that SDK 9.0.0 drops Java 8
and raises the Android minSdk from 21 to 26, linking to the feedback
issues so users can raise concerns before the major release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: Drop the stay-on-8.x line from the SDK 9 warning

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…figs (#6217)

* ref(core): Add MonitorConfigUtils to convert schedules to monitor configs

Framework-free conversion of a 6 field cron expression, fixed rate or
fixed delay into a MonitorConfig, plus period parsing, so the Spring and
Quartz integrations can share it.

* fix(core): Only send monitor configs Sentry reads the same way

Return no config when day of month and day of week are both set, for
cron syntax Sentry rejects, and for zones that are not IANA region IDs.
Whole-hour fixed offsets map to Etc/GMT zones. Intervals use hours or
days when they divide evenly.

* ref(core): Add MonitorConfigUtils.fromSpringScheduled

Move the Spring day-of-week rewrite and the JVM default zone rule into
core so the three Spring modules share them.

* fix(core): Return no config for stepped single value ranges

Spring and Quartz run 10-10/2 only at 10, cronsim steps to the field max.

* fix(core): Read Spring crons per parser and skip fixed delays

Spring before 5.3 steps day of month */n from 0 and can run at midnight
when both day fields are set; read its crons that way. Spring 5.3 runs
#5 in months without a fifth weekday, so return null for it. A fixed
delay drifts from any interval, so it gets no config.

* fix(core): Keep Sunday-only day of week ranges

SUN-SUN was rewritten to 0-7, which crontab reads as every day.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Use a 2 minute check-in margin for crons with fixed seconds

Dropping a non-zero seconds field makes check-ins arrive up to 59s after
the expected minute, which a 1 minute margin barely covers.

---------

Co-authored-by: Claude <noreply@anthropic.com>
…#6215)

* ref(core): Add MonitorConfigUtils to convert schedules to monitor configs

Framework-free conversion of a 6 field cron expression, fixed rate or
fixed delay into a MonitorConfig, plus period parsing, so the Spring and
Quartz integrations can share it.

* fix(core): Only send monitor configs Sentry reads the same way

Return no config when day of month and day of week are both set, for
cron syntax Sentry rejects, and for zones that are not IANA region IDs.
Whole-hour fixed offsets map to Etc/GMT zones. Intervals use hours or
days when they divide evenly.

* ref(core): Add MonitorConfigUtils.fromSpringScheduled

Move the Spring day-of-week rewrite and the JVM default zone rule into
core so the three Spring modules share them.

* fix(core): Return no config for stepped single value ranges

Spring and Quartz run 10-10/2 only at 10, cronsim steps to the field max.

* fix(core): Read Spring crons per parser and skip fixed delays

Spring before 5.3 steps day of month */n from 0 and can run at midnight
when both day fields are set; read its crons that way. Spring 5.3 runs
#5 in months without a fifth weekday, so return null for it. A fixed
delay drifts from any interval, so it gets no config.

* feat(spring): Send monitor config from @scheduled with @SentryCheckIn

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Send @scheduled monitor config by default

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Keep Sunday-only day of week ranges

SUN-SUN was rewritten to 0-7, which crontab reads as every day.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Only catch runtime exceptions when deriving monitor config

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Use pattern-matching instanceof for the @scheduled time unit

* fix(core): Use a 2 minute check-in margin for crons with fixed seconds

Dropping a non-zero seconds field makes check-ins arrive up to 59s after
the expected minute, which a 1 minute margin barely covers.

* fix(spring): Default upsertMonitorConfig to false and read @scheduled like Spring

Existing @SentryCheckIn users shouldn't have their monitors changed on upgrade,
so sending the schedule is opt-in. Find @scheduled with Spring's own lookup so
an overriding method doesn't inherit a parent's schedule.

* chore(changelog): Move the @scheduled monitor config entry to Unreleased

---------

Co-authored-by: Claude <noreply@anthropic.com>
)

* ref(core): Add MonitorConfigUtils to convert schedules to monitor configs

Framework-free conversion of a 6 field cron expression, fixed rate or
fixed delay into a MonitorConfig, plus period parsing, so the Spring and
Quartz integrations can share it.

* fix(core): Only send monitor configs Sentry reads the same way

Return no config when day of month and day of week are both set, for
cron syntax Sentry rejects, and for zones that are not IANA region IDs.
Whole-hour fixed offsets map to Etc/GMT zones. Intervals use hours or
days when they divide evenly.

* ref(core): Add MonitorConfigUtils.fromSpringScheduled

Move the Spring day-of-week rewrite and the JVM default zone rule into
core so the three Spring modules share them.

* fix(core): Return no config for stepped single value ranges

Spring and Quartz run 10-10/2 only at 10, cronsim steps to the field max.

* fix(core): Read Spring crons per parser and skip fixed delays

Spring before 5.3 steps day of month */n from 0 and can run at midnight
when both day fields are set; read its crons that way. Spring 5.3 runs
#5 in months without a fifth weekday, so return null for it. A fixed
delay drifts from any interval, so it gets no config.

* feat(spring): Send monitor config from @scheduled with @SentryCheckIn

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(quartz): Send monitor config from the trigger with check-ins

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Send @scheduled monitor config by default

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(quartz): Send trigger monitor config by default

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Keep Sunday-only day of week ranges

SUN-SUN was rewritten to 0-7, which crontab reads as every day.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Only catch runtime exceptions when deriving monitor config

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(quartz): Catch only expected errors when deriving monitor config

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Use pattern-matching instanceof for the @scheduled time unit

* fix(core): Use a 2 minute check-in margin for crons with fixed seconds

Dropping a non-zero seconds field makes check-ins arrive up to 59s after
the expected minute, which a 1 minute margin barely covers.

* fix(spring): Default upsertMonitorConfig to false and read @scheduled like Spring

Existing @SentryCheckIn users shouldn't have their monitors changed on upgrade,
so sending the schedule is opt-in. Find @scheduled with Spring's own lookup so
an overriding method doesn't inherit a parent's schedule.

* fix(quartz): Send the trigger's monitor config only when opted in

Match @SentryCheckIn: existing check-in users keep their monitors unchanged
unless they set sentry-upsert-monitor-config to "true".

---------

Co-authored-by: Claude <noreply@anthropic.com>
Bumps [com.launchdarkly:launchdarkly-java-server-sdk](https://github.com/launchdarkly/java-core) from 7.13.4 to 7.17.3.
- [Release notes](https://github.com/launchdarkly/java-core/releases)
- [Commits](launchdarkly/java-core@launchdarkly-java-server-sdk-7.13.4...launchdarkly-java-server-sdk-7.17.3)

---
updated-dependencies:
- dependency-name: com.launchdarkly:launchdarkly-java-server-sdk
  dependency-version: 7.17.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ng Boot 3 (#6275)

* ref(core): Add MonitorConfigUtils to convert schedules to monitor configs

Framework-free conversion of a 6 field cron expression, fixed rate or
fixed delay into a MonitorConfig, plus period parsing, so the Spring and
Quartz integrations can share it.

* fix(core): Only send monitor configs Sentry reads the same way

Return no config when day of month and day of week are both set, for
cron syntax Sentry rejects, and for zones that are not IANA region IDs.
Whole-hour fixed offsets map to Etc/GMT zones. Intervals use hours or
days when they divide evenly.

* ref(core): Add MonitorConfigUtils.fromSpringScheduled

Move the Spring day-of-week rewrite and the JVM default zone rule into
core so the three Spring modules share them.

* fix(core): Return no config for stepped single value ranges

Spring and Quartz run 10-10/2 only at 10, cronsim steps to the field max.

* fix(core): Read Spring crons per parser and skip fixed delays

Spring before 5.3 steps day of month */n from 0 and can run at midnight
when both day fields are set; read its crons that way. Spring 5.3 runs
#5 in months without a fifth weekday, so return null for it. A fixed
delay drifts from any interval, so it gets no config.

* feat(spring): Send monitor config from @scheduled with @SentryCheckIn

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Send @scheduled monitor config by default

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Keep Sunday-only day of week ranges

SUN-SUN was rewritten to 0-7, which crontab reads as every day.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Only catch runtime exceptions when deriving monitor config

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring-jakarta): Monitor all @scheduled methods with sentry.monitor-scheduled-tasks

Adds sentry.monitor-scheduled-tasks and sentry.exclude-scheduled-tasks to
Spring Boot 3. Methods without @SentryCheckIn get a slug from the class
and method name and send their @scheduled schedule as the monitor config.

Co-Authored-By: Claude <noreply@anthropic.com>

* changelog

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring-jakarta): Skip reactive @scheduled methods when monitoring all tasks

Spring calls reactive and suspend @scheduled methods once at startup and
subscribes to the result on each run, so check-ins around the call would
only be sent once.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Skip jobs with unsupported schedules when monitoring all jobs

* ref(spring): Use pattern-matching instanceof for the @scheduled time unit

* fix(core): Use a 2 minute check-in margin for crons with fixed seconds

Dropping a non-zero seconds field makes check-ins arrive up to 59s after
the expected minute, which a 1 minute margin barely covers.

* fix(spring): Default upsertMonitorConfig to false and read @scheduled like Spring

Existing @SentryCheckIn users shouldn't have their monitors changed on upgrade,
so sending the schedule is opt-in. Find @scheduled with Spring's own lookup so
an overriding method doesn't inherit a parent's schedule.

* fix(spring): Find @scheduled tasks to monitor the way Spring does

An overriding method without @scheduled isn't scheduled by Spring, so don't
monitor it either.

* feat(spring): Warn when two @scheduled methods share a monitor slug

Derived slugs use only the short class name and method name, so different methods can map to the same slug and share one monitor. Log a warning the first time that happens so users can set an explicit slug.

* ref(spring): Reuse the target class for the slug collision check

Use the same class for the task name and the collision check so both see one value.

* fix(spring): Skip private and static @scheduled methods when monitoring all tasks

Spring invokes private and static scheduled methods on the target, so the proxy never sees them. Don't match them, so they aren't proxied for nothing.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Bumps [com.github.ben-manes.caffeine:jcache](https://github.com/ben-manes/caffeine) from 3.2.0 to 3.3.1.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](ben-manes/caffeine@v3.2.0...v3.3.1)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:jcache
  dependency-version: 3.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ng Boot 2 (#6276)

* ref(core): Add MonitorConfigUtils to convert schedules to monitor configs

Framework-free conversion of a 6 field cron expression, fixed rate or
fixed delay into a MonitorConfig, plus period parsing, so the Spring and
Quartz integrations can share it.

* fix(core): Only send monitor configs Sentry reads the same way

Return no config when day of month and day of week are both set, for
cron syntax Sentry rejects, and for zones that are not IANA region IDs.
Whole-hour fixed offsets map to Etc/GMT zones. Intervals use hours or
days when they divide evenly.

* ref(core): Add MonitorConfigUtils.fromSpringScheduled

Move the Spring day-of-week rewrite and the JVM default zone rule into
core so the three Spring modules share them.

* fix(core): Return no config for stepped single value ranges

Spring and Quartz run 10-10/2 only at 10, cronsim steps to the field max.

* fix(core): Read Spring crons per parser and skip fixed delays

Spring before 5.3 steps day of month */n from 0 and can run at midnight
when both day fields are set; read its crons that way. Spring 5.3 runs
#5 in months without a fifth weekday, so return null for it. A fixed
delay drifts from any interval, so it gets no config.

* feat(spring): Send monitor config from @scheduled with @SentryCheckIn

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Send @scheduled monitor config by default

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Keep Sunday-only day of week ranges

SUN-SUN was rewritten to 0-7, which crontab reads as every day.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Only catch runtime exceptions when deriving monitor config

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring-jakarta): Monitor all @scheduled methods with sentry.monitor-scheduled-tasks

Adds sentry.monitor-scheduled-tasks and sentry.exclude-scheduled-tasks to
Spring Boot 3. Methods without @SentryCheckIn get a slug from the class
and method name and send their @scheduled schedule as the monitor config.

Co-Authored-By: Claude <noreply@anthropic.com>

* changelog

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Monitor all @scheduled methods in Spring Boot 2

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(changelog): Link Spring Boot 2 PR

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring-jakarta): Skip reactive @scheduled methods when monitoring all tasks

Spring calls reactive and suspend @scheduled methods once at startup and
subscribes to the result on each run, so check-ins around the call would
only be sent once.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Skip reactive @scheduled methods when monitoring all tasks

Same fix as the Spring Boot 3 copy.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Skip jobs with unsupported schedules when monitoring all jobs

* fix(spring): Skip jobs with unsupported schedules when monitoring all jobs

* ref(spring): Use pattern-matching instanceof for the @scheduled time unit

* fix(core): Use a 2 minute check-in margin for crons with fixed seconds

Dropping a non-zero seconds field makes check-ins arrive up to 59s after
the expected minute, which a 1 minute margin barely covers.

* fix(spring): Default upsertMonitorConfig to false and read @scheduled like Spring

Existing @SentryCheckIn users shouldn't have their monitors changed on upgrade,
so sending the schedule is opt-in. Find @scheduled with Spring's own lookup so
an overriding method doesn't inherit a parent's schedule.

* fix(spring): Find @scheduled tasks to monitor the way Spring does

An overriding method without @scheduled isn't scheduled by Spring, so don't
monitor it either.

* fix(spring): Find @scheduled tasks to monitor the way Spring does

An overriding method without @scheduled isn't scheduled by Spring, so don't
monitor it either.

* feat(spring): Warn when two @scheduled methods share a monitor slug

Derived slugs use only the short class name and method name, so different methods can map to the same slug and share one monitor. Log a warning the first time that happens so users can set an explicit slug.

* feat(spring): Warn when two @scheduled methods share a monitor slug

Derived slugs use only the short class name and method name, so different methods can map to the same slug and share one monitor. Log a warning the first time that happens so users can set an explicit slug.

* ref(spring): Reuse the target class for the slug collision check

Use the same class for the task name and the collision check so both see one value.

* ref(spring): Reuse the target class for the slug collision check

Use the same class for the task name and the collision check so both see one value.

* fix(spring): Skip private and static @scheduled methods when monitoring all tasks

Spring invokes private and static scheduled methods on the target, so the proxy never sees them. Don't match them, so they aren't proxied for nothing.

* fix(spring): Skip private and static @scheduled methods when monitoring all tasks

Spring invokes private and static scheduled methods on the target, so the proxy never sees them. Don't match them, so they aren't proxied for nothing.

---------

Co-authored-by: Claude <noreply@anthropic.com>
…ng Boot 4 (#6277)

* ref(core): Add MonitorConfigUtils to convert schedules to monitor configs

Framework-free conversion of a 6 field cron expression, fixed rate or
fixed delay into a MonitorConfig, plus period parsing, so the Spring and
Quartz integrations can share it.

* fix(core): Only send monitor configs Sentry reads the same way

Return no config when day of month and day of week are both set, for
cron syntax Sentry rejects, and for zones that are not IANA region IDs.
Whole-hour fixed offsets map to Etc/GMT zones. Intervals use hours or
days when they divide evenly.

* ref(core): Add MonitorConfigUtils.fromSpringScheduled

Move the Spring day-of-week rewrite and the JVM default zone rule into
core so the three Spring modules share them.

* fix(core): Return no config for stepped single value ranges

Spring and Quartz run 10-10/2 only at 10, cronsim steps to the field max.

* fix(core): Read Spring crons per parser and skip fixed delays

Spring before 5.3 steps day of month */n from 0 and can run at midnight
when both day fields are set; read its crons that way. Spring 5.3 runs
#5 in months without a fifth weekday, so return null for it. A fixed
delay drifts from any interval, so it gets no config.

* feat(spring): Send monitor config from @scheduled with @SentryCheckIn

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Send @scheduled monitor config by default

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(core): Keep Sunday-only day of week ranges

SUN-SUN was rewritten to 0-7, which crontab reads as every day.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Only catch runtime exceptions when deriving monitor config

Co-Authored-By: Claude <noreply@anthropic.com>

* ref(spring): Shorten upsertMonitorConfig Javadoc

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring-jakarta): Monitor all @scheduled methods with sentry.monitor-scheduled-tasks

Adds sentry.monitor-scheduled-tasks and sentry.exclude-scheduled-tasks to
Spring Boot 3. Methods without @SentryCheckIn get a slug from the class
and method name and send their @scheduled schedule as the monitor config.

Co-Authored-By: Claude <noreply@anthropic.com>

* changelog

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Monitor all @scheduled methods in Spring Boot 2

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(changelog): Link Spring Boot 2 PR

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(spring): Monitor all @scheduled methods in Spring Boot 4

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(changelog): Link Spring Boot 4 PR

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring-jakarta): Skip reactive @scheduled methods when monitoring all tasks

Spring calls reactive and suspend @scheduled methods once at startup and
subscribes to the result on each run, so check-ins around the call would
only be sent once.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Skip reactive @scheduled methods when monitoring all tasks

Same fix as the Spring Boot 3 copy.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring-7): Skip reactive @scheduled methods when monitoring all tasks

Same fix as the Spring Boot 3 copy.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(spring): Skip jobs with unsupported schedules when monitoring all jobs

* fix(spring): Skip jobs with unsupported schedules when monitoring all jobs

* fix(spring): Skip jobs with unsupported schedules when monitoring all jobs

* ref(spring): Use pattern-matching instanceof for the @scheduled time unit

* fix(spring): Satisfy NullAway in the Spring 7 scheduled check-in advice

* fix(core): Use a 2 minute check-in margin for crons with fixed seconds

Dropping a non-zero seconds field makes check-ins arrive up to 59s after
the expected minute, which a 1 minute margin barely covers.

* fix(spring): Default upsertMonitorConfig to false and read @scheduled like Spring

Existing @SentryCheckIn users shouldn't have their monitors changed on upgrade,
so sending the schedule is opt-in. Find @scheduled with Spring's own lookup so
an overriding method doesn't inherit a parent's schedule.

* fix(spring): Find @scheduled tasks to monitor the way Spring does

An overriding method without @scheduled isn't scheduled by Spring, so don't
monitor it either.

* fix(spring): Find @scheduled tasks to monitor the way Spring does

An overriding method without @scheduled isn't scheduled by Spring, so don't
monitor it either.

* fix(spring): Find @scheduled tasks to monitor the way Spring does

An overriding method without @scheduled isn't scheduled by Spring, so don't
monitor it either.

* feat(spring): Warn when two @scheduled methods share a monitor slug

Derived slugs use only the short class name and method name, so different methods can map to the same slug and share one monitor. Log a warning the first time that happens so users can set an explicit slug.

* feat(spring): Warn when two @scheduled methods share a monitor slug

Derived slugs use only the short class name and method name, so different methods can map to the same slug and share one monitor. Log a warning the first time that happens so users can set an explicit slug.

* feat(spring): Warn when two @scheduled methods share a monitor slug

Derived slugs use only the short class name and method name, so different methods can map to the same slug and share one monitor. Log a warning the first time that happens so users can set an explicit slug.

* ref(spring): Reuse the target class for the slug collision check

Use the same class for the task name and the collision check so both see one value.

* ref(spring): Reuse the target class for the slug collision check

Use the same class for the task name and the collision check so both see one value.

* fix(spring): Skip private and static @scheduled methods when monitoring all tasks

Spring invokes private and static scheduled methods on the target, so the proxy never sees them. Don't match them, so they aren't proxied for nothing.

* fix(spring): Skip private and static @scheduled methods when monitoring all tasks

Spring invokes private and static scheduled methods on the target, so the proxy never sees them. Don't match them, so they aren't proxied for nothing.

* fix(spring): Skip private and static @scheduled methods when monitoring all tasks

Spring invokes private and static scheduled methods on the target, so the proxy never sees them. Don't match them, so they aren't proxied for nothing.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Bumps [com.google.devtools.ksp](https://github.com/google/ksp) from 2.3.9 to 2.3.13.
- [Release notes](https://github.com/google/ksp/releases)
- [Commits](google/ksp@2.3.9...2.3.13)

---
updated-dependencies:
- dependency-name: com.google.devtools.ksp
  dependency-version: 2.3.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the github-actions group with 2 updates: [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.39.1 to 4.39.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@9b32540...1fc58d0)

Updates `github/codeql-action/analyze` from 4.39.1 to 4.39.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@9b32540...1fc58d0)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.39.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.39.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…jects block (#6354)

* build: Apply convention plugins per module instead of the root subprojects block

* docs: Add AndroidX MavenUploadHelper to third-party notices

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
* chore(deps): Bump OkHttp from 4.9.2 to 5.5.1

sentry-okhttp and the Spring Boot integrations still compile against okhttp as compileOnly. The
okhttp3 members they reference are identical for 4.9.2 and 5.5.1, so OkHttp 4 keeps working at
runtime.

OkHttp 5 tries IPv6 first and races routes, which surfaced a bug: connectFailed() marked the
whole call span INTERNAL_ERROR even when OkHttp then connected on another route. It now only
closes the connect timing. callFailed() still reports a call that fails on every route.

sentry-apollo and the Android UI tests stay on mockwebserver 4. Apollo 2 passes a null body to
Response.Builder.body(), and the UI test APK is pinned to the app's okio 2, while OkHttp 5 needs
okio 3.

Fixes JAVA-715

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* changelog

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…nt (#6231)

* fix(okhttp): Don't block on response bodies of unknown length

Capturing a response body for session replay peeked it up front with
`Response.peekBody(MAX_NETWORK_BODY_SIZE + 1)`. OkHttp implements a peek as
`request(byteCount)`, which keeps reading until that many bytes are buffered or
the stream ends. A response with no Content-Length never satisfies either
condition, so for server-sent events, long-poll and any chunked endpoint that
stays open the interceptor never returned and the caller never received the
response at all.

Bodies with a known length still end on their own, so they keep the existing
up-front capture. Bodies of unknown length are now wrapped in a body that
copies what the application consumes into a capped buffer and reports it once
no more bytes can arrive: when the stream ends, when the application closes
the body, or when the cap is reached.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* changelog: reference the pull request

* fix(okhttp): Satisfy detekt for the streaming body capture

Split the capture wrapping into its own function to keep a single return, and
suppress TooManyFunctions on the interceptor as done elsewhere in this module.

* refactor(okhttp): Drop unnecessary locking from the capturing source

A response body has a single consumer, and neither Http1ExchangeCodec.cancel()
nor Http2ExchangeCodec.cancel() closes the body, so nothing reaches this class
from another thread. The AtomicBoolean already guarantees the capture is
reported exactly once.

* fix: Publish late response details safely

A streamed body is only known once it has been consumed, which can be after the
NetworkRequestData carrying it was handed to the scope, so the replay thread can
read it while it is still being written. Keeping the three response values
behind one volatile reference means a reader sees either nothing or the
complete set.

* test: Cover late-filled network request data

* fix(okhttp): Harden the capture of response bodies with no known length

* test(okhttp): Cover async, cancelled and HTTP/2 bodies of unknown length

* ref: Publish both sides of NetworkRequestData the same way

* fix(okhttp): Keep the bytes received before a stream breaks

* ref: Read the response details of a network breadcrumb as one snapshot

* ref(okhttp): Capture every response body through one path

* changelog

* test: Silence R8 for the okhttp types the new response body extends

* ref(okhttp): Rename NetworkBodyCapturingResponseBody to CapturedResponseBody

* ref(okhttp): Capture only the response bytes the application reads

* test(okhttp): Wait for the capture, not for the source handing bytes over

* ref: Keep the status code inside the response details

* ref(okhttp): Restore the original response flow and rethrow fatal capture errors

* ref(okhttp): Drop comments that restate the code

* ref: Drop the constructor comment on ReplayNetworkRequestOrResponse

* Address PR comments

* address PR comments

* test(replay): Pin the response body a late capture leaves out of the replay

---------

Co-authored-by: Carlo Marinangeli <carlo.marinangeli@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
* build: Align SDK modules to one version through sentry-bom

Gradle resolves version conflicts per module, so a build could mix SDK modules
of different versions, for example a newer sentry-android-core with an older
sentry-android-fragment that the Gradle plugin or another library pulled in.
That fails at runtime with NoSuchMethodError or the mixed versions check.

The publish conventions now add sentry-bom as a platform to every published
library module. Gradle then moves all SDK modules of a consumer to the highest
version present. Maven does not apply the dependencyManagement of a
dependency's POM, so Maven builds resolve as before. The BOM now also
constrains sentry-android-distribution, which is released with the SDK.

Refs #5105

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* changelog

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#6041)

* test(time): Publish the TestMonotonicTicker tick to other threads

The ANR tests advance the ticker from the test thread while the watchdog
thread reads it, which without volatile is a data race that can leave the
watchdog looking at a stale tick forever.

* ref(android): Measure ANR thresholds on the monotonic clock (JAVA-579)

The watchdog took its readings from an ICurrentDateProvider lambda over
SystemClock.uptimeMillis(). The type named no clock, so a call site could
not tell what it was measuring, and the arithmetic -- now minus the last
tick, compared against a threshold -- was spelled out inline.

MonotonicClock and Deadline replace both: the clock is a named type, and
the watchdog asks the question it actually cares about, which is whether
the main thread has missed its window.

The clock counts deep sleep, which uptimeMillis() did not, so a suspend
between posting the ticker and checking it now looks like a missed
window. It cannot fabricate an ANR: the watchdog reports only once
ActivityManager confirms the process is NOT_RESPONDING, and on resume the
main thread runs the ticker that is already queued.

* ref(android): Measure ANR profiling on the monotonic clock (JAVA-579)

Same reasoning as the watchdog: the suspicion and ANR thresholds are now
read from a named clock rather than SystemClock, and injecting it lets the
tests drive it directly instead of going through Robolectric's shadow
clock.

Deep sleep cannot inflate the measurement here either, because the polling
thread parks itself while the app is backgrounded and resets the baseline
when it wakes.

* changelog

* ref(time): Supply the ANR ticker through MonotonicTickerProvider (JAVA-579)

Both ANR detectors resolved AndroidMonotonicTicker.getInstance() themselves,
so each call site named the concrete Android ticker and neither could be
pointed at another one. SentryAndroidOptions already knows which ticker the
platform wants, but it is final, so a test cannot override the getter.

Add a one-method MonotonicTickerProvider that SentryOptions implements.
ANRWatchDog gains a static factory that reads its timeout, debug behavior,
logger and ticker off options, replacing the telescoping convenience
constructor. AnrProfilingIntegration installs the ticker in register(),
which drops the two constructors it had grown and leaves the public no-arg
constructor and sentry-android-core.api unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ref(android): Require an installed ticker for ANR profiling (JAVA-579)

Drop the JavaMonotonicTicker fallback. On Android nanoTime() stops while the
device is suspended, so a default that is never meant to be used would measure
main-thread stalls against the wrong clock if it ever were.

Start the test ticker at a non-zero origin. A fake that starts at zero makes a
reading taken against a different origin indistinguishable from a correct one,
which is the mistake this whole change exists to prevent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ref(android): Pass the ANR profiling ticker directly (JAVA-579)

MonotonicTickerProvider only existed so a test could hand
AnrProfilingIntegration a fake ticker. A package-private method taking
the ticker does the same without a new core interface or a change to
the SentryOptions supertype.

Also rename the ANRWatchDog test that claimed to cover a device suspend:
the Android ticker counts suspend, so the test only shows the threshold
is measured on the injected ticker rather than wall time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ref(android): Read the ANR profiling ticker from options (JAVA-579)

Tests spy SentryAndroidOptions to supply a TestMonotonicTicker, so the
package-private installTicker seam is no longer needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ref(android): Drop the UnnecessaryLambda suppression in ANR profiling (JAVA-579)

Error Prone does not run on sentry-android-core, so the suppression had no effect. The lambda
field stays: removeCallbacks matches the posted Runnable by identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ording (#6486)

* fix(okhttp): Don't block on response bodies of unknown length

Capturing a response body for session replay peeked it up front with
`Response.peekBody(MAX_NETWORK_BODY_SIZE + 1)`. OkHttp implements a peek as
`request(byteCount)`, which keeps reading until that many bytes are buffered or
the stream ends. A response with no Content-Length never satisfies either
condition, so for server-sent events, long-poll and any chunked endpoint that
stays open the interceptor never returned and the caller never received the
response at all.

Bodies with a known length still end on their own, so they keep the existing
up-front capture. Bodies of unknown length are now wrapped in a body that
copies what the application consumes into a capped buffer and reports it once
no more bytes can arrive: when the stream ends, when the application closes
the body, or when the cap is reached.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* changelog: reference the pull request

* fix(okhttp): Satisfy detekt for the streaming body capture

Split the capture wrapping into its own function to keep a single return, and
suppress TooManyFunctions on the interceptor as done elsewhere in this module.

* refactor(okhttp): Drop unnecessary locking from the capturing source

A response body has a single consumer, and neither Http1ExchangeCodec.cancel()
nor Http2ExchangeCodec.cancel() closes the body, so nothing reaches this class
from another thread. The AtomicBoolean already guarantees the capture is
reported exactly once.

* fix: Publish late response details safely

A streamed body is only known once it has been consumed, which can be after the
NetworkRequestData carrying it was handed to the scope, so the replay thread can
read it while it is still being written. Keeping the three response values
behind one volatile reference means a reader sees either nothing or the
complete set.

* test: Cover late-filled network request data

* fix(okhttp): Harden the capture of response bodies with no known length

* test(okhttp): Cover async, cancelled and HTTP/2 bodies of unknown length

* ref: Publish both sides of NetworkRequestData the same way

* fix(okhttp): Keep the bytes received before a stream breaks

* ref: Read the response details of a network breadcrumb as one snapshot

* ref(okhttp): Capture every response body through one path

* changelog

* test: Silence R8 for the okhttp types the new response body extends

* ref(okhttp): Rename NetworkBodyCapturingResponseBody to CapturedResponseBody

* ref(okhttp): Capture only the response bytes the application reads

* test(okhttp): Wait for the capture, not for the source handing bytes over

* ref: Keep the status code inside the response details

* ref(okhttp): Restore the original response flow and rethrow fatal capture errors

* ref(okhttp): Drop comments that restate the code

* ref: Drop the constructor comment on ReplayNetworkRequestOrResponse

* Address PR comments

* address PR comments

* test(replay): Pin the response body a late capture leaves out of the replay

* fix(okhttp): Capture network details only while Session Replay is recording

* changelog

---------

Co-authored-by: Carlo Marinangeli <carlo.marinangeli@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
* ci: skip duplicate high-risk code PR comments

Only post the high-risk code warning once per PR, matching sentry-dart.

Co-Authored-By: Gino Buenaflor <giancarlo.buenaflor@sentry.io>
Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* ci: paginate high-risk comment lookup

Avoid missing an existing warning when a PR has more than 30 comments.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* ci: null-safe high-risk comment body check

Avoid TypeError if a PR comment has a null body.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* ci: update high-risk comment when file list changes

Keep a single warning comment and refresh its body so reviewers
do not see a stale high-risk file list after later pushes.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* ci: preserve high-risk comment checkboxes on update

Only rewrite the warning when the high-risk file set changes, and keep
reviewer checkbox state for files that remain.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* ci: fix high-risk comment checklist parsing

Drop the leading space before the file list and allow optional
indent so the first checklist item is not skipped on parse.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: Gino Buenaflor <giancarlo.buenaflor@sentry.io>
Co-authored-by: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>
* docs: Allow broad catches only at SDK boundaries

Inside the SDK, catch the narrowest type. Broad catches are allowed only
at boundaries where the thrown types are unknowable, must call
rethrowIfFatal first, and must document what happens on failure. Align
BUGBOT.md with AGENTS.md so Bugbot enforces the same policy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Make some changes

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…Sauce Labs UI job (#6492)

* ci(android): Run UI tests incl. replay on API 35 in AGP matrix, drop Sauce Labs UI job

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* ci(android): Pull replay snapshots even when the AGP matrix UI tests fail

android-emulator-runner runs each script line in its own shell and stops at
the first failing line, so a failing connectedReleaseAndroidTest skipped the
snapshot pull. Run the tests and the pull from one script that exits with the
tests' status.

#skip-changelog

* ci(android): Drop --daemon from the AGP matrix UI test run

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

#skip-changelog

* ci(android): Run the AGP matrix UI tests on API 30 google_apis

API 30 google_apis captures replay frames with PixelCopy (verified in
#6495) and avoids the Android 15 ART method-tracing crash that the
profiling tests hit on API 35.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* test(profiling): Run checkTimedOutProfile on emulators with a shorter timeout

The emulator skip was added in #3074 because the timed-out profile's
trace file was sometimes missing on emulators. Since #3478 timed-out
profiles are discarded and the test asserts no profile is sent, so it
no longer reads a trace file. Drop the skip, and add a test-only hook
to shorten the 30s profiling timeout so the test waits 5s instead of 35s.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

* test(uitest): Remove checkTimedOutProfile

The test only checks that a timed-out transaction profile is discarded,
which AndroidProfilerTest and AndroidTransactionProfilerTest already cover.
It was skipped on emulators, so nothing in CI ran it after the Sauce Labs
job was removed. Also reverts the test-only profiling timeout hook.

Co-Authored-By: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: Roman Zavarnitsyn <roman.zavarnitsyn@sentry.io>
…e the SDK build (#6391)

* build(samples): Prepare the samples to build outside the SDK build

The samples and Android integration tests are about to become their own
builds, which include the SDK build. Several things tie them to the SDK
build today:

- They call buildSrc's Config, which other builds cannot see. They now
  name the coordinates directly, the way a customer's build would.
- Five samples' shadowJar tasks use buildSrc's MergeSpringMetadataAction,
  which only the samples use. It moves to build-logic, which the new
  builds can include.
- They pick the Kotlin stdlib version with KotlinCompilerVersion, a
  compiler-internal class that came from buildSrc's classpath. They now
  use KGP's getKotlinPluginVersion(), which returns the same version.
- AGP came from Config.AGP on the root buildscript classpath. A composite
  build must use a single AGP version, so it now comes from the version
  catalog, and each build's settings applies the AGP matrix job's
  VERSION_AGP override.
- The javac -Xlint:all -Werror flags came from the root allprojects
  block. They move to the io.sentry.jdk-target convention, which every
  subproject already applies and the new builds can apply too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Apply suggestion from @romtsn

* build(samples): Move the Android sample to its own build

The Android sample is now a standalone Gradle build that includes the SDK
build. It depends on io.sentry:* coordinates, which Gradle substitutes with
the SDK's projects, so there is nothing to publish first. The SDK build
doesn't include it back, so the sample's plugins (KSP, SQLDelight, Room,
CameraX) no longer load in the SDK build.

The macrobenchmark moves into the sample's build, because AGP requires a
benchmark and the app it targets to be in the same build.

Root check and spotlessApply no longer reach the sample, so preMerge runs
the sample build's check, and the format workflow runs its spotlessApply.
That check covers what the root check ran for it: lint, unit tests,
SQLDelight migrations and spotless.

Run it with ./gradlew -p sentry-samples/sentry-samples-android <task>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Run the Android sample's check in its own workflow

Instead of adding it to `make preMerge`, which the SDK's Build job runs,
a new Samples workflow runs the Android sample build's `check` as its own
job. A broken sample then fails its own check, it runs in parallel with
the SDK build, and the Build job doesn't get longer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Drop the Gradle encryption key and buildSrc cache from the Samples workflow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Check out the default ref without submodules in the Samples workflow

The head-SHA ref only matters for build.yml's snapshot upload, and the
repository has had no submodules since #3189.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Link the Android sample's Gradle files to the SDK build's

gradle.properties, gradlew, gradle/wrapper and
gradle/gradle-daemon-jvm.properties are now symlinks to the SDK build's
files. Both builds pick the same daemon JDK and JVM arguments, so they
can share a daemon, and the sample reads the SDK version from the
versionName property instead of parsing the root file.

The copied gradle.properties had drifted from the root one (-Xmx6g and
CrashOnOutOfMemoryError instead of -Xmx8g and HeapDumpOnOutOfMemoryError).

Dependabot also scans the sample build, so the Develocity plugins in its
settings stay current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Drop the JUnit report step from the Samples workflow

The samples and integration test builds have no unit tests, and
phoenix-actions/test-reporting fails the job when it finds no JUnit XML,
even with fail-on-error set to false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Bring back make format for every build

The root spotlessApply can't reach the Android sample, because the SDK
build doesn't include it. make format runs spotlessApply in the root and
in the sample build, and the format workflow, AGENTS.md, CONTRIBUTING.md
and the create-java-pr skill use it. CONTRIBUTING.md already documented
make format, which #4476 removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Read the sample's SDK version through the catalog

The sample's settings now add versionName to the catalog as
libs.versions.sentry, as the other separate builds do, and use the root
build's Develocity plugin version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Use the setup-gradle version of the other workflows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Drop the comment on the macrobenchmark's target project

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Drop the header comment from the Android sample's settings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Move the Android integration tests to their own build

sentry-uitest-android, sentry-uitest-android-critical and test-app-size
are now a standalone Gradle build that includes the SDK build, like the
Android sample. They depend on io.sentry:* coordinates, which Gradle
substitutes with the SDK's projects, including the unpublished
sentry-test-support. The SDK build doesn't include them back, so SAGP,
errorprone's uitest checks and their AndroidX test dependencies no longer
load in the SDK build.

AGP stays shared: a composite build can only use one AGP version, so the
AGP matrix job's VERSION_AGP still applies to both builds.

Root check and spotlessApply no longer reach these apps, so preMerge runs
this build's check, which covers what the root check ran for them: lint,
detekt and spotless. The format workflow runs its spotlessApply, and the
AGP matrix, UI test and size workflows call it with -p. APK paths don't
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Run the Android integration tests' check in the Samples workflow

Adds the integration tests build to the Samples workflow's matrix instead
of a `make preMerge` target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build: Drop the root's SAGP declaration and local SAGP repository

With the Android sample and integration tests in their own builds, no
project in the SDK build applies the Sentry Android Gradle Plugin. The
root no longer declares it or looks it up in mavenLocal when useSagp is
set; those builds declare it and handle useSagp themselves.

The root keeps the AGP declaration: the SDK's Android modules apply
com.android.library without a version and get AGP from it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Link the integration tests' Gradle files to the SDK build's

gradle.properties, gradlew, gradle/wrapper and
gradle/gradle-daemon-jvm.properties are now symlinks to the SDK build's
files, as in the Android sample. The copied gradle.properties had drifted
from the root one (-Xmx6g and CrashOnOutOfMemoryError), and the build had
no wrapper or daemon JDK pin. The SDK version now comes from the shared
versionName property instead of parsing the root file.

The root drops android.experimental.lint.version. It equals the lint
bundled with AGP 9.4.0, so it changes nothing for the SDK build, and
sentry-uitest-android's warningsAsErrors fails on it once the integration
tests share the root gradle.properties.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Include each integration test project on its own line

Adding or removing a project then changes only its own line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Keep the integration tests' Develocity and dependency versions current

The integration tests' settings use the root build's Develocity plugin
version, and Dependabot also scans their build, as it does the Android
sample's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Drop the comment on the integration tests' root plugins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Drop the header comment from the integration tests' settings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Roman Zavarnitsyn <rom4ek93@gmail.com>
Bumps androidx.browser:browser from 1.8.0 to 1.10.0.

---
updated-dependencies:
- dependency-name: androidx.browser:browser
  dependency-version: 1.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…uild (#6394)

* build(samples): Move the JVM samples to their own build

The 28 JVM samples are now a standalone Gradle build in sentry-samples
that includes the SDK build, like the Android sample and the Android
integration tests. They depend on io.sentry:* coordinates, which Gradle
substitutes with the SDK's projects. The SDK build doesn't include them
back, so the Spring Boot, gretty and shadow plugins the samples apply no
longer load in the SDK build.

The three bootRunWithAgent tasks find the agent jar from the repository
root and take the SDK version from the catalog, since the samples build
has its own root directory and gradle.properties.

With no samples or integration tests left in the SDK build, the name
filters that skipped them for publishing and CodeQL go too.

Root check and spotlessApply no longer reach the samples, so preMerge runs
this build's check, which covers what the root check ran for them:
compilation, jars and spotless. The format workflow runs its
spotlessApply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Link the JVM samples' Gradle files to the SDK build's

gradle.properties, gradlew, gradle/wrapper and
gradle/gradle-daemon-jvm.properties are now symlinks to the SDK build's
files, as in the Android sample and integration test builds. The copied
gradle.properties had drifted from the root one (-Xmx6g and
CrashOnOutOfMemoryError), and the build had no wrapper or daemon JDK pin.

The settings read the SDK version from the shared versionName property,
use the root build's Develocity plugin version, and include each sample
on its own line, matching the other separate builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Apply the convention plugins in each JVM sample

Each sample applies io.sentry.spotless and io.sentry.jdk-target in its
own plugins block, as the modules of the other separate builds do,
instead of the root script applying them to every subproject.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(samples): Check the JVM samples in the Samples workflow

The JVM samples' check runs as its own job in the Samples workflow, like
the other separate builds, instead of through checkSamples in make
preMerge, so it no longer lengthens the required Build job. Dependabot
scans their build too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build: Drop the root's Spring dependency-management declaration

With the JVM samples in their own build, no project in the SDK build
applies io.spring.dependency-management.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Drop the comment on the JVM samples' root plugins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Drop the header comment from the JVM samples' settings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build(samples): Declare the servlet sample's SDK version before using it

The dependencies block read sentryVersion before its declaration ran, so the
sample asked for io.sentry:sentry-servlet:null. The composite build substitutes
the SDK project by group and name, which hid it, but resolving published
artifacts would fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(deps): bump sqliteRc from 2.7.0-rc01 to 2.8.0-alpha03

Bumps `sqliteRc` from 2.7.0-rc01 to 2.8.0-alpha03.

Updates `androidx.sqlite:sqlite-bundled` from 2.7.0-rc01 to 2.8.0-alpha03

Updates `androidx.sqlite:sqlite-framework` from 2.7.0-rc01 to 2.8.0-alpha03

---
updated-dependencies:
- dependency-name: androidx.sqlite:sqlite-bundled
  dependency-version: 2.8.0-alpha03
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: androidx.sqlite:sqlite-framework
  dependency-version: 2.8.0-alpha03
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(samples): Bump Android sample minSdk to 24 for androidx.sqlite 2.8

androidx.sqlite 2.8.0 declares minSdk 24, which breaks the sample's
manifest merge. The SDK itself still supports minSdk 21.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(samples): Use overrideLibrary for androidx.sqlite 2.8 instead of minSdk bump

Keep the sample at minSdk 23 and force the androidx.sqlite 2.8 modules
(which declare minSdk 24) through the manifest merger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Roman Zavarnitsyn <rom4ek93@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(graphql): support specification error types

* fix(graphql): Make specification filtering opt-in

Add an explicit option before matching ignored GraphQL error types against
classification specifications. Keep the existing behavior unchanged by
default to avoid suppressing errors based on custom specification output.

Expose the option through the Spring Boot GraphQL configuration.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(graphql): Move changelog entry to Unreleased

Keep the GraphQL specification filtering change in the current release notes instead of modifying the already released 8.56.0 section.

Refs GH-6092

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Alexander Dinauer <adinauer@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Bumps the github-actions group with 4 updates: [actions/setup-java](https://github.com/actions/setup-java), [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [getsentry/craft](https://github.com/getsentry/craft).


Updates `actions/setup-java` from 6.1.0 to 6.2.0
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](actions/setup-java@b843ebf...77dd5b2)

Updates `github/codeql-action/init` from 4.39.2 to 4.39.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@1fc58d0...33d7b85)

Updates `github/codeql-action/analyze` from 4.39.2 to 4.39.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@1fc58d0...33d7b85)

Updates `getsentry/craft` from 3.9.0 to 3.11.1
- [Release notes](https://github.com/getsentry/craft/releases)
- [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md)
- [Commits](getsentry/craft@2e29b08...866c07c)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 6.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.39.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.39.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: getsentry/craft
  dependency-version: 3.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…6088)

* docs(time): Steer new measurements at the io.sentry.time clock APIs

Document on each singleton clock's getInstance() that callers should read
the ticker or wall clock off the options object instead, so they get the
per-platform implementation rather than pinning themselves to one. Calling
JavaMonotonicTicker.getInstance() on Android is the trap worth naming: it
stops counting through a device suspend, so intervals spanning a deep sleep
come out short.

Add an AGENTS.md section so new measurement code reaches for io.sentry.time
rather than DateUtils.getCurrentDateTime() or a SentryDateProvider, picks the
abstraction by what the number is for, and treats adding a new abstraction as
a deliberate step rather than a way around an awkward call site.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(time): Shorten the Measuring Time section in AGENTS.md

Name the legacy clock interfaces instead of listing their
implementations, which also covers ICurrentDateProvider. Drop the
table's notes column and the history of why the old types remain, and
cut the two rules to a sentence each. The getInstance() Javadoc already
carries the detail where callers see it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(time): Shorten the getInstance() Javadoc on the clock singletons

Drop the paragraph on when getInstance() may still be called directly.
Only the options accessors and test support do, so it restated the
code. Keep the one reason that matters: JavaMonotonicTicker stops
counting while an Android device is suspended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Lint checks the build root's gradle-wrapper.properties in a single
module it picks per build. Since the integration tests moved into their
own build, that module is sentry-uitest-android, which treats warnings
as errors. AndroidGradlePluginVersion compares the wrapper with the
latest Gradle release online, so the Gradle 9.9.0 release turned the
Samples workflow red on main without any change on our side.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…6514)

Replace the string coordinates and the Config.Libs constants with catalog entries. Both stay versionless: Spring BOMs manage aspectjweaver and the Kotlin plugin manages kotlin-reflect.

sentry-apollo-4 pinned kotlin-reflect to 2.0.0 in tests, but mockito-kotlin already pulled in 2.1.20, so the pin had no effect. It now resolves to 2.3.21, the same version as stdlib.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
dependabot Bot and others added 13 commits November 9, 2026 11:29
…6504)

* chore(deps): bump androidx.appcompat:appcompat from 1.3.0 to 1.8.0

Bumps androidx.appcompat:appcompat from 1.3.0 to 1.8.0.

---
updated-dependencies:
- dependency-name: androidx.appcompat:appcompat
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* build(deps): Use AppCompat 1.7.1 for API 21 compatibility

Keep the Android sample and UI test app on an AppCompat release that supports minSdk 21. AppCompat 1.8.0 requires API 23 and fails the UI test app manifest merge.

Refs #6504
Co-Authored-By: Codex <codex@openai.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Adam Brown <adam.brown@sentry.io>
Co-authored-by: Codex <codex@openai.com>
…#6500)

* fix(android): Don't block the main thread on the frame metrics looper

SentryFrameMetricsCollector waited on HandlerThread.getLooper() at the first
startCollection(), blocking Activity.onCreate for hundreds of ms on a busy device.
Create the handler in onLooperPrepared() instead, and start the thread at init when
frames tracking will use it, so its looper is ready before the first frame.

Fixes #6443

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* changelog

* fix(android): Read the current frame metrics window once per check

trackCurrentWindow() now also runs on the HandlerThread in onLooperPrepared(). Reading
the volatile currentWindow twice could NPE if onActivityStopped nulled it in between,
killing the thread before Looper.loop() and silently stopping frame metrics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…red (#6485)

Only Nav3Activity applied the sample's settings (screen tracking, user-interaction transactions and breadcrumbs) to the SDK options. When Android restored the process straight into Nav3ProductsActivity, Nav3CheckoutActivity, or Nav3FragmentsActivity, the options stayed at the app's init defaults, which have user-interaction tracing on. Each of those Activities now applies the configuration from its intent extras in onCreate.
* fix(profiling): Accept dots in the JVM profiling traces dir path

JavaContinuousProfiler refused any traces directory whose path held one
of 26 characters, including ".", so a cache dir like /home/app/.sentry
or /opt/my.app logged "Disabling profiling". async-profiler only treats
"," (its argument separator) and "%" (file name patterns) specially, so
those are the only characters it still rejects.

The check also only stopped the first start: init() marked itself done
before validating and returned true from then on, so later starts went
ahead with the rejected options. It now remembers the result, as the
Android profiler does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* changelog

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(opentelemetry): Honor OTEL_BSP_SCHEDULE_DELAY in the agent

The agent built Sentry's BatchSpanProcessor with the OpenTelemetry
default, so spans always reached Sentry in 5 second batches, whatever
otel.bsp.schedule.delay said. Read it from the agent's config instead.

The Boot 4 agent suites set it to 100ms. Each of their tests waited for
a 5 second batch, which made them take minutes on CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* changelog

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(spring-boot): Shorten the span batch delay in the Boot 2 and Boot 3 agent suites

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Update CHANGELOG.md

Co-authored-by: Alexander Dinauer <adinauer@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Alexander Dinauer <adinauer@users.noreply.github.com>
Bumps the github-actions group with 1 update: [getsentry/craft](https://github.com/getsentry/craft).


Updates `getsentry/craft` from 3.11.1 to 3.11.2
- [Release notes](https://github.com/getsentry/craft/releases)
- [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md)
- [Commits](getsentry/craft@866c07c...9567926)

---
updated-dependencies:
- dependency-name: getsentry/craft
  dependency-version: 3.11.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps androidx.core:core-ktx from 1.7.0 to 1.19.1.

---
updated-dependencies:
- dependency-name: androidx.core:core-ktx
  dependency-version: 1.19.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [com.toasttab.android:gummy-bears-api-21](https://github.com/open-toast/gummy-bears) from 0.12.0 to 0.16.0.
- [Release notes](https://github.com/open-toast/gummy-bears/releases)
- [Commits](open-toast/gummy-bears@0.12.0...0.16.0)

---
updated-dependencies:
- dependency-name: com.toasttab.android:gummy-bears-api-21
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps androidx.constraintlayout:constraintlayout from 2.2.1 to 2.2.2.

---
updated-dependencies:
- dependency-name: androidx.constraintlayout:constraintlayout
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…tro more startup time (#6491)

* ci(ui-tests): Key the AVD cache on the emulator version and give Maestro more startup time

* ci(ui-tests): Read the emulator version from source.properties

* Adjust MAESTRO_DRIVER_STARTUP_TIMEOUT for emulator

Reduced MAESTRO_DRIVER_STARTUP_TIMEOUT from 120s to 60s to accommodate cold-boot scenarios.
Co-Authored-By: Nelson Osacky <nelson.osacky@sentry.io>
@sentry-junior
sentry-junior Bot requested review from a team and adinauer as code owners November 10, 2026 08:52
@sentry-junior
sentry-junior Bot requested review from markushi and romtsn and removed request for a team November 10, 2026 08:52
@sentry

sentry Bot commented Nov 10, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.63.0 (1) release

⚙️ sentry-android Build Distribution Settings

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8f6ee96. Configure here.

@runningcode
runningcode merged commit 2033c63 into 9.x.x Nov 10, 2026
41 of 42 checks passed
@runningcode
runningcode deleted the sync/main-to-9.x.x-2026-11-10 branch November 10, 2026 09:12
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.

7 participants