Note
Will be released in 9.9.1
Description
Native app start spans (Cold Start, Process Initialization, Application.onCreate, etc.) are missing from the "root /" transaction when Time to Full Display (TTFD) tracking takes longer than 3 seconds to complete.
The app_start_cold/app_start_warm measurements are correctly reported, but the detailed span breakdown is missing.
Environment
- Platform: iOS and Android (both affected)
- SDK: sentry_flutter
- Affected versions: At least 9.8.0 (likely earlier versions too)
Root Cause
Race condition in NativeAppStartHandler where _attachAppStartSpans() is called after timeToDisplayTracker.track(), but the transaction can be sent inside the timeToDisplayTracker.track() await chain via _finishedCallback.
Timeline:
- Transaction created with
autoFinishAfter: 3 seconds
- Timer fires at 3s, sets
_finishStatus to "finishing"
- When TTFD completes (>3s),
_finishedCallback triggers finish() and sends the transaction
_attachAppStartSpans() runs after timeToDisplayTracker.track() returns — too late!
What's Present vs Missing
| Data |
Present? |
Reason |
app_start_cold measurement |
✅ |
Added before timeToDisplayTracker.track() |
app_start_type data |
✅ |
Added before timeToDisplayTracker.track() |
| TTID/TTFD spans |
✅ |
Created inside timeToDisplayTracker.track() |
Cold Start span |
❌ |
Added after (too late) |
| Native spans (Process Init, etc.) |
❌ |
Added after (too late) |
First frame render span |
❌ |
Added after (too late) |
Reproduction
- Enable TTFD tracking:
options.enableTimeToFullDisplayTracing = true
- Call
reportFullyDisplayed() after 3+ seconds (or don't call it at all)
- Check the "root /" transaction in Sentry
- Native app start spans will be missing
// In your app's root widget initState:
Future.delayed(const Duration(seconds: 5), () {
SentryFlutter.reportFullyDisplayed();
});
// Result: Native app start spans will be MISSING## Suggested Fix
// Move `_attachAppStartSpans()` **before** `timeToDisplayTracker.track()`:
// Current (buggy):
await options.timeToDisplayTracker.track(...);
await _attachAppStartSpans(...); // Too late!
// Fixed:
await _attachAppStartSpans(...); // Add spans first
await options.timeToDisplayTracker.track(...);Alternatively, use the `onFinish` callback to ensure spans are attached before the transaction is captured (as mentioned in the existing TODO comment).
Note
Will be released in
9.9.1Description
Native app start spans (Cold Start, Process Initialization, Application.onCreate, etc.) are missing from the "root /" transaction when Time to Full Display (TTFD) tracking takes longer than 3 seconds to complete.
The
app_start_cold/app_start_warmmeasurements are correctly reported, but the detailed span breakdown is missing.Environment
Root Cause
Race condition in
NativeAppStartHandlerwhere_attachAppStartSpans()is called aftertimeToDisplayTracker.track(), but the transaction can be sent inside thetimeToDisplayTracker.track()await chain via_finishedCallback.Timeline:
autoFinishAfter: 3 seconds_finishStatusto "finishing"_finishedCallbacktriggersfinish()and sends the transaction_attachAppStartSpans()runs aftertimeToDisplayTracker.track()returns — too late!What's Present vs Missing
app_start_coldmeasurementtimeToDisplayTracker.track()app_start_typedatatimeToDisplayTracker.track()timeToDisplayTracker.track()Cold StartspanFirst frame renderspanReproduction
options.enableTimeToFullDisplayTracing = truereportFullyDisplayed()after 3+ seconds (or don't call it at all)