[Solved] Garmin Running Dynamics streams (GCT, Vertical Oscillation, Vertical Ratio, GCT Balance) not populated despite being present in the FIT file

Title: Garmin Running Dynamics streams (GCT, Vertical Oscillation, Vertical Ratio, GCT Balance) not populated on custom fields despite being present in the FIT file

Hi everyone,

I’m seeing a consistent issue where Garmin Running Dynamics data (Ground Contact Time, Vertical Oscillation, Vertical Ratio, GCT Balance, etc.) is not appearing in Intervals.icu, even though I’ve confirmed the data is genuinely present and valid in the original FIT file.

Setup

  • Device: Garmin Enduro 3, built-in running dynamics (no footpod)
  • Note: this watch is currently opted into Garmin’s beta firmware program, so it’s possible (though I have no direct evidence either way) that this is related to a beta-specific FIT encoding change rather than a general Enduro 3 issue
  • External HR sensor: Polar HRM (ANT+), software_version 1.1
  • Garmin device software_version: 22.38
  • Activity: a recent run, manually exported from Garmin Connect (“Export Original”) and re-uploaded to Intervals.icu after first noticing the issue via the standard Garmin auto-sync

What I did to isolate the problem

  1. I set up the relevant custom streams/fields/charts for Garmin Running Dynamics (the public ones shared by the community, e.g. “Garmin GCT”, “Garmin Vertical Oscillation”) and ran a full re-analysis. The fields stayed empty.
  2. I used the streamsCheck() Activity Field JS console script (credit to miguell, shared in this thread) to check icu.streams directly on the activity. Result:
| Variable Name                   | Length | Type      | Status
|---------------------------------|--------|-----------|--------
| heartrate                       |   3816 | Array     | ✅
| speed                           |   3816 | Array     | ✅
| power                           |   3816 | Array     | ✅
| time                            |   3816 | Array     | ✅
| altitude                        |   3816 | Array     | ✅
| distance                        |   3816 | Array     | ✅
| gps                             |   3816 | Array     | ✅
| grade                           |   3816 | Array     | ✅
| cadence_row                     |   3816 | Array     | ✅
| garmin_vo_row (GarminVO)        |      0 | Array     | ❌
| garmin_gct (GarminGCT)          |      0 | Array     | ❌
| garmin_vertical_ratio           |      0 | Array     | ❌
| garmin_step_length_row          |      0 | Array     | ❌
| garmin_gct_balance              |      0 | Array     | ❌
| garmin_gct_percent              |      0 | Array     | ❌
| garmin_gap_pace                 |      0 | Array     | ❌
| garmin_impact_load              |      0 | Array     | ❌
| garmin_step_speed_loss          |      0 | Array     | ❌
| garmin_step_speed_loss_percent  |      0 | Array     | ❌

Availability: 47.4% (9/19)

All standard streams are complete (3816 samples), but every single Garmin-specific running dynamics stream comes back empty.

  1. To rule out a device/firmware-side recording issue, I parsed the original FIT file directly with fitparse (Python) outside of Intervals.icu entirely. The relevant record message fields are:
stance_time (def_num=41):           3777 / 3816 samples non-null (~99%)
stance_time_balance (def_num=84):   present (sparser, as expected for GCT balance)
stance_time_percent (def_num=40):   present
vertical_oscillation (def_num=39):  3783 / 3816 samples non-null (~99%)
vertical_ratio (def_num=83):        present alongside vertical_oscillation

Sample values for context (early in the run): stance_time ≈ 280–299 ms, vertical_oscillation ≈ 58–60 mm, vertical_ratio ≈ 7.5–8.4%. The handful of nulls are only in the first few and last few seconds of the recording, which is expected (sensor/algorithm warm-up), not a recording failure.

Conclusion

The FIT file itself contains complete, valid Running Dynamics data straight from the watch. The data is simply not being mapped into Intervals.icu’s internal stream model (GarminGCT, GarminVO, GarminVerticalRatio, etc. all show length 0), even after a manual FIT upload and full re-analysis. This points to a parsing/mapping gap on the Intervals.icu side for this combination of device (Enduro 3, built-in running dynamics, no footpod), possibly related to how these particular FIT fields are encoded by this device/firmware version versus other Garmin watches where the community-shared custom fields apparently do work.

Cross-check with another platform

As a final sanity check, I uploaded the exact same FIT file to Runalyze. It parses and displays the full Running Dynamics panel without any issue.

Runalyze’s lap/splits table also breaks this down per kilometer and the values are fully consistent across the run .

This confirms the data is not just technically present in the file, but is also fully usable/interpretable by at least one other major platform.

Not a recent regression

I went back and checked my historical running activities on Intervals.icu (synced over time, well before I started investigating this specific run), every single one shows the same pattern: standard streams complete, all Garmin running dynamics streams empty. I hadn’t actively used Intervals.icu before recently, which is why I never noticed this until now, but it doesn’t look like something that broke with a recent release. it appears to have been the case consistently for as long as I’ve had this device connected.

I’ve uploaded the original FIT file here: Microsoft OneDrive

Thanks.

For fit fields/streams you have to reprocess. Reanalysing is not enough.

Thanks, but I’d already gone further than that actually I deleted the activity and readded it manually from the original FIT file), and also ran reprocess after reading your reply. Same result, all Garmin Running Dynamics fields still come back empty.

I’ve downloaded your file and uploaded it and it works for me.

I’ve used the Garmin GCT stream from @miguell

Found it (sort of). I created a brand new account and manually uploaded the same FIT file there, and the streams show up correctly. So this is account-specific, not file-specific.Currently digging through account/profile settings and custom fields to find what’s different. Will report back once I find it. Really thanks too much.

The thing I can think of… if there is a custom stream or field which fails (e.g. memory limit exceeded error), the processing of the activity stops and all streams afterwards aren’t calculated. So maybe check if all streams above are correctly processed.

That did it, I removed all custom streams/fields and re-added them using Miguell’s Garmin set, problem’s gone now.

Thanks a lot for the help, much appreciated :folded_hands: