Skip to content

Fix HTML trailing newline accessibility crash#145

Merged
malkoG merged 1 commit intohackers-pub:mainfrom
dalinaum:fix/html-trailing-newline-accessibility-crash
Apr 22, 2026
Merged

Fix HTML trailing newline accessibility crash#145
malkoG merged 1 commit intohackers-pub:mainfrom
dalinaum:fix/html-trailing-newline-accessibility-crash

Conversation

@dalinaum
Copy link
Copy Markdown
Contributor

Summary

  • Trim only trailing rendered line breaks from parsed HTML AnnotatedString output.
  • Preserve interior newlines and paragraph/list formatting while avoiding a trailing text boundary that can crash Compose accessibility.
  • Add regression tests for trailing <br> and compact list output.

Crash Context

Crashlytics issue: https://console.firebase.google.com/u/0/project/hackerspub-android/crashlytics/app/android:pub.hackers.android/issues/970e0c4edebb1afa31c7867b373dec64?time=7d&types=crash&sessionEventKey=69E6FD270331000138BB1A3827BF86CE_2209511287297688744

Relevant stack trace path:

Fatal Exception: java.lang.IllegalArgumentException: Found paragraph index -2 should be in range [0, 1).
Debug info: index=2420, paragraphs=[[0, 2420)]
  at androidx.compose.ui.text.MultiParagraphKt.findParagraphByIndex(MultiParagraph.kt:1244)
  at androidx.compose.ui.text.MultiParagraph.getBoundingBox(MultiParagraph.kt:647)
  at androidx.compose.ui.text.TextLayoutResult.getBoundingBox(TextLayoutResult.kt:503)
  at androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat.addExtraDataToAccessibilityNodeInfoHelper(AndroidComposeViewAccessibilityDelegateCompat.android.kt:1785)

The key detail is index=2420 with paragraphs=[[0, 2420)]: accessibility requested a character bounding box at the paragraph end boundary. That boundary can happen when our HTML parser leaves a trailing rendered newline in a ClickableText node. A trailing newline is part of the text range but does not have a drawable glyph bounding box inside the laid-out paragraph.

This looks like a Compose text/accessibility bug as well: Compose should defensively ignore the request or return null for that character-location entry instead of crashing the app. Since the app can avoid feeding this vulnerable trailing boundary without changing user-visible content, this PR normalizes the parsed HTML output by trimming only trailing \n characters.

Verification

./gradlew testDebugUnitTest --tests pub.hackers.android.ui.components.HtmlContentKtTest
BUILD SUCCESSFUL

Crashlytics: https://console.firebase.google.com/u/0/project/hackerspub-android/crashlytics/app/android:pub.hackers.android/issues/970e0c4edebb1afa31c7867b373dec64?time=7d&types=crash&sessionEventKey=69E6FD270331000138BB1A3827BF86CE_2209511287297688744

The reported crash comes from Compose accessibility while resolving character locations for text: AndroidComposeViewAccessibilityDelegateCompat.addExtraDataToAccessibilityNodeInfoHelper() calls TextLayoutResult.getBoundingBox(), which reaches MultiParagraph.getBoundingBox() and throws IllegalArgumentException: Found paragraph index -2 should be in range [0, 1). The debug info shows index=2420 with paragraphs=[[0, 2420)], so accessibility asked for the paragraph end boundary rather than a drawable character inside the paragraph.

This appears to be a Compose text/accessibility bug: a trailing newline at the end of a Text/ClickableText layout can be treated as part of the accessibility text range, but it has no glyph bounding box in the laid-out paragraph. Compose should defensively ignore or null out that character-location request instead of crashing the app.

Normalize parsed HTML by trimming only trailing rendered line breaks from the AnnotatedString. Interior newlines and paragraph spacing are preserved, while HTML parser artifacts such as Hello<br> or compact lists ending in a final newline no longer expose the vulnerable trailing boundary to Compose accessibility.

Tests cover trailing <br> and compact list output.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 83e0d7cf-9ec1-4b6c-826d-c6e67b66dcbc

📥 Commits

Reviewing files that changed from the base of the PR and between 31cf139 and b33f087.

📒 Files selected for processing (2)
  • app/src/main/java/pub/hackers/android/ui/components/HtmlContent.kt
  • app/src/test/java/pub/hackers/android/ui/components/HtmlContentKtTest.kt

📝 Walkthrough

Walkthrough

The parseHtmlToAnnotatedString function now post-processes its result by removing trailing newline characters through a new private extension AnnotatedString.trimTrailingLineBreaks(). Unit tests were added to verify the trimming behavior with HTML inputs ending in <br> tags and list elements.

Changes

Cohort / File(s) Summary
HTML Content Post-processing
app/src/main/java/pub/hackers/android/ui/components/HtmlContent.kt
Added private extension function trimTrailingLineBreaks() that post-processes AnnotatedString to remove trailing \n characters by finding the last non-newline index and returning a subsequence.
HTML Content Unit Tests
app/src/test/java/pub/hackers/android/ui/components/HtmlContentKtTest.kt
Added two test cases verifying that parseHtmlToAnnotatedString removes trailing newlines from HTML input ending with <br> tags and from unordered list elements.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: fixing a crash caused by trailing newlines in HTML parsing affecting accessibility.
Description check ✅ Passed The description comprehensively explains the problem, root cause, solution, and provides verification details directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@malkoG malkoG merged commit 0025b25 into hackers-pub:main Apr 22, 2026
2 checks passed
@dalinaum dalinaum deleted the fix/html-trailing-newline-accessibility-crash branch April 22, 2026 15:10
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.

2 participants