You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Health Connect import, Live Bluetooth (strap connected)
Test Centre profile
Not a test-mode bug
What happens
The workout detail card and overview does not show all details like avg HR.
What you expected instead
As the HR data is shown on the chart it can be calculated. I expect it to be shown always.
This is true for manual activities and health connect (but not all!).
Steps to reproduce
Go to workouts. Some have data, others don't.
Strap log
Before you submit
I attached my exported NOOP .zip (not a screenshot of the Live screen). If my bug is a clearly reproducible UI issue I described exactly how to see it instead.
I attached or pasted a strap log above — or my bug is a clearly reproducible UI issue that doesn't need one (e.g. a typo, a button that does nothing) and I've described exactly how to see it.
I checked the Troubleshooting guide — especially "history syncs but no data" (most often the strap isn't banking history to flash; charge it to 100% and reconnect).
I checked the FAQ and — if I'm on a WHOOP 5.0 / MG — the 5.0/MG status page, and this isn't an already-known limit (e.g. SpO₂, or recovery/sleep on the 5/MG).
I've left out anything personal (strap serial, account email, raw export).
Reproduced by inspection — thanks, the "chart has the data" observation is what pins it.
The chart and the average read different tables. The chart uses WhoopDao.hrSamples, which UNIONs measured hrSample with PPG-derived ppgHrSample (#156, so a PPG-only WHOOP 5 window still has a trace). The average comes from WhoopDao.hrWindowStats, which is SELECT COUNT(*), AVG(bpm), MAX(bpm) FROM hrSample — measured rows only, no PPG.
fillWorkoutHrFromStrap needs 60 samples before it will show a number. On a 5.0 the firmware picks v26 PPG vs v18 HR per second, so a PPG-heavy workout can have a full chart and still count under 60 measured rows — average stays blank. That explains all three of your observations: 5.0-specific, "some have data, others don't" (depends on PPG density in that window), and manual and Health Connect both affected — they pass through the same gate.
iOS doesn't have this bug. Its twin (Repository.fillWorkoutHrFromStrap) reads store.hrSamples, the coalescing read. So this is also a cross-platform parity break: same data, different number.
The Android query looks like it was written as an optimisation — aggregate in SQL instead of materialising up to 8000 rows — and dropped the PPG union in the process.
Fix is to aggregate over the same union the chart uses. I'll put up a PR.
One thing your export would settle: whether these specific workouts are PPG-heavy. If you still have the .zip, it would confirm the diagnosis rather than leave it inferred — but the code path is clear enough that I'm not blocking on it.
The cause: three of the four things that read a workout's HR window (chart, zone minutes, Effort) counted measured ∪ PPG-derived samples; the fourth — the one behind Avg HR — counted measured only. On a 5.0, where the firmware banks v26 PPG instead of v18 HR per second, that meant a full chart and a blank average on the same workout. Effort was blocked by the same 60-sample gate, which is why it was "all details" and not just avg HR.
All four now read the same rows.
@bartmuskala — this will be in the next staging build. Two things would help:
Confirm it on your side. The affected workouts should show both Avg HR and Effort. Note the fix only changes what is displayed — nothing is rewritten — so existing workouts should just start showing numbers, no re-import needed.
If any stay blank, that would be a different cause and worth knowing. The export would settle it — I diagnosed this from the code path rather than from your data, so I can't rule out a second reason behind some of them.
Reopening — that close was automatic ("Fixes #836" in the PR body), not a judgement that this is confirmed done.
The fix is merged and the mechanism is established from the code, but I diagnosed it from the code path rather than from @bartmuskala's data, so I would rather it stay open until someone confirms it on a build. Closing it now would claim a verification nobody has done.
I don't think it is fully solved.
After updating I still see missing data.
So I resynced health connect.
Now it shows calories correct (another bug I shared before #835 tagat was solved?) but HR is gone everywhere also where it showed data.
After waiting a while I see the data popping up but still only for part of the activities: not for manual, not for all HC workouts.
I will check again in a while to see if it was just delayed.
Activity
ryanbr commentedon Jul 26, 2026
Reproduced by inspection — thanks, the "chart has the data" observation is what pins it.
The chart and the average read different tables. The chart uses
WhoopDao.hrSamples, which UNIONs measuredhrSamplewith PPG-derivedppgHrSample(#156, so a PPG-only WHOOP 5 window still has a trace). The average comes fromWhoopDao.hrWindowStats, which isSELECT COUNT(*), AVG(bpm), MAX(bpm) FROM hrSample— measured rows only, no PPG.fillWorkoutHrFromStrapneeds 60 samples before it will show a number. On a 5.0 the firmware picks v26 PPG vs v18 HR per second, so a PPG-heavy workout can have a full chart and still count under 60 measured rows — average stays blank. That explains all three of your observations: 5.0-specific, "some have data, others don't" (depends on PPG density in that window), and manual and Health Connect both affected — they pass through the same gate.iOS doesn't have this bug. Its twin (
Repository.fillWorkoutHrFromStrap) readsstore.hrSamples, the coalescing read. So this is also a cross-platform parity break: same data, different number.The Android query looks like it was written as an optimisation — aggregate in SQL instead of materialising up to 8000 rows — and dropped the PPG union in the process.
Fix is to aggregate over the same union the chart uses. I'll put up a PR.
One thing your export would settle: whether these specific workouts are PPG-heavy. If you still have the .zip, it would confirm the diagnosis rather than leave it inferred — but the code path is clear enough that I'm not blocking on it.
fix(workouts): count PPG-derived HR in the workout window stats (#836)
fix(workouts): aggregate the workout HR window on iOS too, uncapped (#…
fix(workouts): count PPG-derived HR in the workout window stats (#841)
ryanbr commentedon Jul 26, 2026
Fixed in #841, merged as
fbdffdaf.The cause: three of the four things that read a workout's HR window (chart, zone minutes, Effort) counted measured ∪ PPG-derived samples; the fourth — the one behind Avg HR — counted measured only. On a 5.0, where the firmware banks v26 PPG instead of v18 HR per second, that meant a full chart and a blank average on the same workout. Effort was blocked by the same 60-sample gate, which is why it was "all details" and not just avg HR.
All four now read the same rows.
@bartmuskala — this will be in the next staging build. Two things would help:
Leaving this open until you have confirmed.
ryanbr commentedon Jul 26, 2026
Reopening — that close was automatic ("Fixes #836" in the PR body), not a judgement that this is confirmed done.
The fix is merged and the mechanism is established from the code, but I diagnosed it from the code path rather than from @bartmuskala's data, so I would rather it stay open until someone confirms it on a build. Closing it now would claim a verification nobody has done.
bartmuskala commentedon Jul 27, 2026
I don't think it is fully solved.
After updating I still see missing data.
So I resynced health connect.
Now it shows calories correct (another bug I shared before #835 tagat was solved?) but HR is gone everywhere also where it showed data.
After waiting a while I see the data popping up but still only for part of the activities: not for manual, not for all HC workouts.
I will check again in a while to see if it was just delayed.
Let me know which logs you need.
bartmuskala commentedon Jul 27, 2026
Please find some logs attached.
noop-workouts-Android-v9.2.0-staging-260727-1150.zip
noop-import-Android-v9.2.0-staging-260727-1149.zip
bartmuskala commentedon Jul 28, 2026
This morning I noticed two differences - I did not make any changes or resynced or whatever.
bartmuskala commentedon Jul 28, 2026
Now I checked again. It's back 🤔.
bartmuskala commentedon Jul 29, 2026
In 9.2.2 it seems to be solid and stable. All HC imported workouts have data.
The manual ones have not. Also see request #928
fix(android): manual workouts read HR under the active strap union, n…
11 remaining items
test centre: adb-like detailed capture — rolling on-device strap-log …
analyze: halve the idle backstop re-score cadence to 30 min (ryanbr#836…
perf(analyzeRecent): per-day in-memory reuse cache — fix #1005 re-sco…
perf(analyzeRecent): per-day in-memory reuse cache — fix #1005 re-sco…
diag(rr): reuse the two collapses the sweep duplicated, and print a g…
diag(rr): pre-storage R-R census + same-second tolerance sweep (#1008/#…
perf(launch): budget the workout HR reconcile, and make the analyze g…
Restore the undo set in ONE rescore, and never crash on an empty strip (
Edit a bridged night across all its fragments, not just the winning o…
Tally per second, and a width the multiply can't outgrow (#1505)
Android: fill imported workout HR under the active strap (#1606)
sleep: sort the bpm axis once, not once per percentile
health: backfill the skin-temp absolutes the 21-night window never re…
health: the absolutes backfill never ran on the installs that need it (…
today: stop the Liquid Effort tile calling a load index a percentage