Bug description
SfPdfViewer crashes in release builds with a fatal TypeError: Null check operator used on a null value inside SfPdfViewerState._checkVisiblePages, leaving the user staring at a blank white viewer. The crash originates from the unguarded null-assert lookups on the internal page-layout map:
// pdfviewer.dart (33.2.12 lines ~4103-4111; byte-identical in 34.1.33)
final Rect pageRect = Rect.fromLTWH(
_scrollDirection == PdfScrollDirection.vertical
? 0
: _pdfPages[pageNumber]!.pageOffset,
_scrollDirection == PdfScrollDirection.vertical
? _pdfPages[pageNumber]!.pageOffset // <-- crash site (line 4108)
: 0,
_pdfPages[pageNumber]!.pageSize.width,
_pdfPages[pageNumber]!.pageSize.height,
);
Why it happens (race): _pdfPages is repopulated during widget builds and cleared on document reset/swap, while _getTileImage schedules a delayed Timer(Durations.medium4) whose callback calls _checkVisiblePages. That callback iterates for (pageNumber = _pdfViewerController.pageNumber; pageNumber <= _pdfViewerController.pageCount; pageNumber++) and null-asserts _pdfPages[pageNumber]!. If the timer fires in a window where the map is non-empty but not (yet) complete for every page ≤ pageCount — e.g. around a rebuild/reload boundary — the ! throws. The if (_pdfPages.isEmpty) return; guard at the top of _checkVisiblePages only protects against the fully-cleared state, not the partially-populated one.
The crash is strongly amplified by large, image-heavy documents: in our fleet it fires almost exclusively on ~4.3 MB, 28-page PDFs where nearly every page carries a full-page background image (generated by TCPDF/FPDI). Slower build/layout/render passes make the delayed tile timer far more likely to land inside a bad window. It reproduces on high-end devices (Galaxy S24/S25 Ultra), so it is a timing race, not a low-memory/low-CPU issue.
Because the exception escapes through the timer callback to PlatformDispatcher.onError, onDocumentLoadFailed never fires and the app has no way to recover the viewer — end users just see a blank screen. Our crash reporter has 182 occurrences across 20 users for this exact signature (first seen Oct 2024, still occurring on 33.2.12).
Possibly related (same method, different line): #2552 reports extractText() crashing inside the same _checkVisiblePages loop; #1816 reported the sibling _getTileImage/_getSpecificTile null-assert in 2024 but was closed for lack of information.
Suggested fix: treat a missing _pdfPages[pageNumber] entry as "layout not ready yet" and skip it — the next tile-timer tick re-runs _checkVisiblePages anyway:
final PdfPageInfo? pageInfo = _pdfPages[pageNumber];
if (pageInfo == null) {
continue;
}
(and equivalently for the other _pdfPages[...]! sites in _checkVisiblePages / the single-page-layout variant).
Steps to reproduce
We do not have a minimal deterministic repro — it is a timing race. Conditions under which we observe it in production:
- Load a large, image-heavy PDF (ours: 28 pages, ~4.3 MB, full-page raster background on nearly every page) via
SfPdfViewer.network inside a Scaffold (form-filling screen, canShowSignaturePadDialog: false).
- Open the document and interact normally (scroll/zoom) around load/rebuild boundaries.
- Intermittently, the delayed tile-render timer fires while the page-layout map is incomplete → fatal
TypeError, blank viewer. Reopening the screen usually works on a later attempt.
We can share a sample document with equivalent structure privately through a support ticket if needed.
Code sample
Code sample
SfPdfViewer.network(
presignedUrl, // ~4.3 MB, 28-page PDF, full-page images on most pages
controller: _controller,
canShowSignaturePadDialog: false,
onDocumentLoaded: (_) => _onDocumentLoaded(),
onFormFieldFocusChange: _onFieldFocusChange,
onFormFieldValueChanged: _onTextChanged,
)
Screenshots or Video
Not applicable — the user-visible symptom is a blank white viewer body after the fatal error.
Stack Traces
Stack Traces
Captured by Sentry from a release (AOT) build, mechanism: PlatformDispatcher.onError, level: fatal:
TypeError: Null check operator used on a null value
at SfPdfViewerState._checkVisiblePages (pdfviewer.dart:4108)
at SfPdfViewerState._getTileImage (pdfviewer.dart:4621)
at new Future.delayed.<fn> (future.dart:440)
at TickerFuture.whenCompleteOrCancel.thunk (ticker.dart:464)
at _Timer._runTimers (timer_impl.dart:423)
at _Timer._handleMessage (timer_impl.dart:454)
at _RawReceivePort._handleMessage (isolate_patch.dart:192)
Line 4108 of syncfusion_flutter_pdfviewer-33.2.12/lib/src/pdfviewer.dart is the ? _pdfPages[pageNumber]!.pageOffset expression quoted above; line 4621 is the _checkVisiblePages() call inside _getTileImage.
Recent occurrences observed on: SM-S928U (Android 16), SM-S938U, SM-S916U, SM-S906U1, SM-S711U, SM-F731U, SM-A176U — all Android 15/16, Flutter 3.44.4/3.44.6 stable, Dart 3.12.2, package 33.2.12.
On which target platforms have you observed this bug?
Android (release/AOT builds; observed on Android 15 and 16)
Flutter Doctor output
Doctor output
Flutter 3.44.6 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ee80f08bbf
Dart 3.12.2 • DevTools 2.54.1
syncfusion_flutter_pdfviewer: 33.2.12 (crash site verified byte-identical in 34.1.33)
Bug description
SfPdfViewercrashes in release builds with a fatalTypeError: Null check operator used on a null valueinsideSfPdfViewerState._checkVisiblePages, leaving the user staring at a blank white viewer. The crash originates from the unguarded null-assert lookups on the internal page-layout map:Why it happens (race):
_pdfPagesis repopulated during widget builds and cleared on document reset/swap, while_getTileImageschedules a delayedTimer(Durations.medium4)whose callback calls_checkVisiblePages. That callback iteratesfor (pageNumber = _pdfViewerController.pageNumber; pageNumber <= _pdfViewerController.pageCount; pageNumber++)and null-asserts_pdfPages[pageNumber]!. If the timer fires in a window where the map is non-empty but not (yet) complete for every page ≤ pageCount — e.g. around a rebuild/reload boundary — the!throws. Theif (_pdfPages.isEmpty) return;guard at the top of_checkVisiblePagesonly protects against the fully-cleared state, not the partially-populated one.The crash is strongly amplified by large, image-heavy documents: in our fleet it fires almost exclusively on ~4.3 MB, 28-page PDFs where nearly every page carries a full-page background image (generated by TCPDF/FPDI). Slower build/layout/render passes make the delayed tile timer far more likely to land inside a bad window. It reproduces on high-end devices (Galaxy S24/S25 Ultra), so it is a timing race, not a low-memory/low-CPU issue.
Because the exception escapes through the timer callback to
PlatformDispatcher.onError,onDocumentLoadFailednever fires and the app has no way to recover the viewer — end users just see a blank screen. Our crash reporter has 182 occurrences across 20 users for this exact signature (first seen Oct 2024, still occurring on 33.2.12).Possibly related (same method, different line): #2552 reports
extractText()crashing inside the same_checkVisiblePagesloop; #1816 reported the sibling_getTileImage/_getSpecificTilenull-assert in 2024 but was closed for lack of information.Suggested fix: treat a missing
_pdfPages[pageNumber]entry as "layout not ready yet" and skip it — the next tile-timer tick re-runs_checkVisiblePagesanyway:(and equivalently for the other
_pdfPages[...]!sites in_checkVisiblePages/ the single-page-layout variant).Steps to reproduce
We do not have a minimal deterministic repro — it is a timing race. Conditions under which we observe it in production:
SfPdfViewer.networkinside aScaffold(form-filling screen,canShowSignaturePadDialog: false).TypeError, blank viewer. Reopening the screen usually works on a later attempt.We can share a sample document with equivalent structure privately through a support ticket if needed.
Code sample
Code sample
Screenshots or Video
Not applicable — the user-visible symptom is a blank white viewer body after the fatal error.
Stack Traces
Stack Traces
Captured by Sentry from a release (AOT) build,
mechanism: PlatformDispatcher.onError,level: fatal:Line 4108 of
syncfusion_flutter_pdfviewer-33.2.12/lib/src/pdfviewer.dartis the? _pdfPages[pageNumber]!.pageOffsetexpression quoted above; line 4621 is the_checkVisiblePages()call inside_getTileImage.Recent occurrences observed on: SM-S928U (Android 16), SM-S938U, SM-S916U, SM-S906U1, SM-S711U, SM-F731U, SM-A176U — all Android 15/16, Flutter 3.44.4/3.44.6 stable, Dart 3.12.2, package 33.2.12.
On which target platforms have you observed this bug?
Android (release/AOT builds; observed on Android 15 and 16)
Flutter Doctor output
Doctor output