Skip to content

ADFA-2593 | Fix initialization crash in BuildOutputFragment#866

Merged
jatezzz merged 5 commits intostagefrom
fix/ADFA-2593-build-output-crash
Jan 29, 2026
Merged

ADFA-2593 | Fix initialization crash in BuildOutputFragment#866
jatezzz merged 5 commits intostagefrom
fix/ADFA-2593-build-output-crash

Conversation

@jatezzz
Copy link
Collaborator

@jatezzz jatezzz commented Jan 21, 2026

Description

Fixed a race condition causing an ArrayIndexOutOfBoundsException when opening the Build Output fragment with pending logs.

The crash occurred because the code attempted to append text to the IDEEditor before its internal layout components (specifically LineBreakLayout) were fully initialized and measured.

Changes:

  • Introduced an extension property isReadyToAppend to verify if the editor is attached to the window and laid out.
  • Moved the pending output flushing logic to a post runnable to ensure the view cycle is complete before modification.
  • Refactored the appending logic into flushPendingOutputIfReady using Kotlin scope functions for better null safety.

Details

Logic update to prevent the following crash reported in Sentry:
java.lang.ArrayIndexOutOfBoundsException: index = 0, length = 0 at io.github.rosemoe.sora.util.BlockIntList.set

Before changes

Screen.Recording.2026-01-20.at.3.53.57.PM.mov

After changes

Screen.Recording.2026-01-21.at.11.17.03.AM.mov

Ticket

ADFA-2593

Observation

The isReadyToAppend check specifically looks for isLaidOut to guarantee that the editor knows its dimensions before calculating line breaks.

@jatezzz jatezzz requested a review from a team January 21, 2026 16:23
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough
  • Overview

    • Fixes race condition (ADFA-2593) that caused java.lang.ArrayIndexOutOfBoundsException when opening Build Output with pending logs by ensuring text is appended only after IDEEditor layout/measurement is ready.
  • Key changes

    • editor/IDEEditor.kt
      • Added val isReadyToAppend: Boolean = !isReleased && isAttachedToWindow && isLaidOut && width > 0.
      • Added suspend fun awaitLayout(onForceVisible: () -> Unit) to suspend until editor has valid dimensions.
      • Added fun appendBatch(text: String) which safely appends text (wrapped in runCatching).
    • app/.../BuildOutputFragment.kt
      • Replaced per-line immediate UI updates with a coroutine-driven batched pipeline using an UNLIMITED Channel and a background processLogs() coroutine.
      • appendOutput(output) now enqueues lines into the channel instead of updating the editor directly.
      • Added batching/newline normalization helpers (ensureNewline, drainTo) and a drain-to-batch approach to reduce main-thread work.
      • Added flushToEditor(text) that switches to Dispatchers.Main, awaits layout readiness (with a timeout), then calls editor.appendBatch(text) and updates empty-state visibility.
      • Replaced ThreadUtils with lifecycleScope + coroutines.
  • Benefits

    • Eliminates the Sora ArrayIndexOutOfBoundsException by waiting for editor layout before appending.
    • Reduces main-thread work and layout thrashing via background batching.
    • Improves null-safety and exception containment around editor updates.
  • Risks, regressions & best-practice notes

    • Layout heuristic limits: isLaidOut && width > 0 may miss some nested-measurement edge cases — keep Sentry monitoring active.
    • Unbounded channel: Channel.UNLIMITED can grow without bound under heavy logging; consider bounding or backpressure to prevent memory spikes.
    • Lifecycle coupling: ensure the channel/coroutine are correctly tied to fragment/editor lifecycle to avoid leaks or lost logs during rapid detach/attach.
    • Silent failures: appendBatch suppresses exceptions via runCatching; these should be logged or reported to avoid hiding rendering issues.
    • Behavioral change: batching alters timing/interleaving of logs compared to immediate per-line appends; validate UX expectations and tests.
  • Impact

    • Severity: fixes a critical initialization crash in build output viewing.
    • Scope: internal changes to BuildOutputFragment and IDEEditor; non-breaking to public API.
    • Compatibility: backward-compatible; log timing/formatting may differ slightly due to batching.

Walkthrough

BuildOutputFragment now buffers log lines into an unbounded coroutine Channel and runs a background coroutine to batch and flush them to IDEEditor; IDEEditor gained awaitLayout, isReadyToAppend, and appendBatch helpers to safely coordinate UI appends.

Changes

Cohort / File(s) Summary
Build output fragment (async pipeline)
app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt
Replaced immediate per-line UI updates with a coroutine-driven batching pipeline: added logChannel: Channel<String>(UNLIMITED), processLogs() background consumer, helpers (ReceiveChannel<String>.drainTo(), String.ensureNewline()), and flushToEditor() which uses awaitLayout and Main dispatcher. Switched from ThreadUtils to lifecycleScope/coroutines.
Editor readiness and batching
editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.kt
Added val isReadyToAppend: Boolean, suspend fun awaitLayout(onForceVisible: () -> Unit), and fun appendBatch(text: String) to support safe, suspended layout wait and batched appends. Added necessary coroutine/View imports.

Sequence Diagram(s)

sequenceDiagram
  participant Producer as Log Producer\n(BuildOutputFragment)
  participant Channel as logChannel
  participant Processor as processLogs()\n(Background)
  participant Editor as IDEEditor\n(UI/Main)

  Producer->>Channel: appendOutput(line)
  Channel-->>Processor: receive lines / drainTo(batch)
  Processor->>Processor: accumulate batch
  Processor->>Editor: flushToEditor(batch)
  Editor->>Editor: awaitLayout(onForceVisible)
  Editor->>Editor: appendBatch(batch)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • itsaky-adfa
  • dara-abijo-adfa

Poem

🐇
I queued my whispers down a cozy chute,
Coroutines hummed and gathered every route,
Batches snug, each newline tucked,
I hopped them up and gently plucked,
Logs hopped out tidy, soft, and cute.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main fix: addressing an initialization crash in BuildOutputFragment using the ticket reference.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the root cause, the specific crash, the solution, and including relevant ticket references.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`:
- Around line 68-78: flushPendingOutputIfReady currently appends raw
unsavedLines causing missing newline normalization that appendOutput() enforces;
update flushPendingOutputIfReady (or extract a shared helper used by
appendOutput and flushPendingOutputIfReady) to normalize each line to end with a
newline before calling editor.append, e.g., reuse the same newline logic applied
in appendOutput for each item in unsavedLines, then clear unsavedLines and call
emptyStateViewModel.setEmpty(false) as before.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt (1)

39-76: Append can still run before layout; queue until ready.

Line 47‑61 appends as soon as editor != null. If output arrives between view creation and first layout, the same crash can still occur. Also, unsavedLines can be mutated off the UI thread while flushPendingOutputIfReady() iterates. Consider gating appendOutput() on isReadyToAppend and synchronizing unsavedLines.

🛠️ Proposed fix
 fun appendOutput(output: String?) {
-	if (editor == null) {
-		unsavedLines.add(output)
-		return
-	}
+	val currentEditor = editor
+	if (currentEditor == null || !currentEditor.isReadyToAppend) {
+		synchronized(unsavedLines) { unsavedLines.add(output) }
+		currentEditor?.post { flushPendingOutputIfReady() }
+		return
+	}
 	ThreadUtils.runOnUiThread {
 		val message =
 			if (output == null || output.endsWith("\n")) {
 				output
 			} else {
 				"${output}\n"
 			}
-		editor?.append(message).also {
+		currentEditor.append(message).also {
 			emptyStateViewModel.setEmpty(false)
 		}
 	}
 }
 
 private fun flushPendingOutputIfReady() {
 	editor?.run {
-		if (!isReadyToAppend || unsavedLines.isEmpty()) return
-
-		unsavedLines.forEach { line ->
-			line?.let {
-				append(if (it.endsWith("\n")) it else "$it\n")
-			}
-		}
-		unsavedLines.clear()
+		if (!isReadyToAppend) return
+		val lines =
+			synchronized(unsavedLines) {
+				if (unsavedLines.isEmpty()) null
+				else unsavedLines.toList().also { unsavedLines.clear() }
+			} ?: return
+
+		lines.forEach { line ->
+			line?.let { append(if (it.endsWith("\n")) it else "$it\n") }
+		}
 		emptyStateViewModel.setEmpty(false)
 	}
 }

@jatezzz jatezzz force-pushed the fix/ADFA-2593-build-output-crash branch 3 times, most recently from 89349fe to cc33a83 Compare January 22, 2026 14:05
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":401,"request":{"method":"PATCH","url":"https://api.github.com/repos/appdevforall/CodeOnTheGo/issues/comments/3779384517","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- This is an auto-generated comment: rate limited by coderabbit.ai -->\n\n> [!WARNING]\n> ## Rate limit exceeded\n> \n> `@jatezzz` has exceeded the limit for the number of commits that can be reviewed per hour. Please wait **14 minutes and 23 seconds** before requesting another review.\n> \n> <details>\n> <summary>⌛ How to resolve this issue?</summary>\n> \n> After the wait time has elapsed, a review can be triggered using the `@coderabbitai review` command as a PR comment. Alternatively, push new commits to this PR.\n> \n> We recommend that you space out your commits to avoid hitting the rate limit.\n> \n> </details>\n> \n> \n> <details>\n> <summary>🚦 How do rate limits work?</summary>\n> \n> CodeRabbit enforces hourly rate limits for each developer per organization.\n> \n> Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.\n> \n> Please see our [FAQ](https://docs.coderabbit.ai/faq) for further information.\n> \n> </details>\n> \n> \n\n<!-- end of auto-generated comment: rate limited by coderabbit.ai -->\n\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nDeferred build-output flushing: pending output lines are no longer appended immediately in onViewCreated; they are flushed later via a posted task that checks the editor's readiness (`isReadyToAppend`) before appending and clearing the pending queue.\n\n## Changes\n\n| Cohort / File(s) | Summary |\n|---|---|\n| **Build output fragment** <br> `app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt` | Replaced immediate flush of `unsavedLines` in `onViewCreated` with `editor?.post { flushPendingOutputIfReady() }`. Added `private fun flushPendingOutputIfReady()` to append pending lines only when `isReadyToAppend` is true, ensure trailing newline, clear `unsavedLines`, and update the empty-state flag. |\n| **Editor readiness flag** <br> `editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.kt` | Added public computed property `val isReadyToAppend: Boolean` with getter `get() = !isReleased && isAttachedToWindow && isLaidOut` used to gate deferred flush. |\n\n## Sequence Diagram(s)\n\n(omitted — changes do not introduce a multi-component sequential feature requiring visualization)\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~20 minutes\n\n## Suggested reviewers\n\n- itsaky-adfa\n- Daniel-ADFA\n\n## Poem\n\n> 🐰  \n> I held my lines beneath the log,  \n> Sat patient in the editor's fog,  \n> A gentle post, a readiness check,  \n> Then newline hops — no line was wrecked,  \n> I twitched my whiskers, output snug.\n\n</details>\n\n<!-- walkthrough_end -->\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 2 | ❌ 1</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning)</summary>\n\n|     Check name     | Status     | Explanation                                                                          | Resolution                                                                         |\n| :----------------: | :--------- | :----------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- |\n| 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. |\n\n</details>\n<details>\n<summary>✅ Passed checks (2 passed)</summary>\n\n|     Check name    | Status   | Explanation                                                                                                                                                                                       |\n| :---------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|    Title check    | ✅ Passed | The title clearly and specifically summarizes the main change: fixing an initialization crash in BuildOutputFragment, which aligns with the core objective of resolving the race condition issue. |\n| Description check | ✅ Passed | The description is comprehensive and directly related to the changeset, explaining the crash cause, the solution approach, and providing concrete references to the issue and changes made.       |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=appdevforall/CodeOnTheGo&utm_content=866)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":1}},"response":{"url":"https://api.github.com/repos/appdevforall/CodeOnTheGo/issues/comments/3779384517","status":401,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","connection":"close","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Thu, 22 Jan 2026 14:05:58 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-media-type":"github.v3; format=json","x-github-request-id":"402A:AC459:C7EBE1:382E7E7:69722EC6","x-xss-protection":"0"},"data":{"message":"Requires authentication","documentation_url":"https://docs.github.com/rest","status":"401"}}}

@jatezzz jatezzz force-pushed the fix/ADFA-2593-build-output-crash branch 6 times, most recently from 7966702 to 03a22ba Compare January 27, 2026 13:20
@jatezzz jatezzz requested a review from Daniel-ADFA January 27, 2026 18:39
@jatezzz jatezzz force-pushed the fix/ADFA-2593-build-output-crash branch from 7dd38e4 to d3b88ea Compare January 27, 2026 19:50
@jatezzz jatezzz force-pushed the fix/ADFA-2593-build-output-crash branch from 02df537 to ab33f3a Compare January 28, 2026 13:07
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/itsaky/androidide/fragments/output/BuildOutputFragment.kt`:
- Around line 112-123: The flushToEditor coroutine can lose logs when
awaitLayout times out because appendBatch is skipped; update flushToEditor (the
function named flushToEditor) to detect whether append actually happened and
return a Boolean success flag instead of void: after awaitLayout/or its timeout,
check the editor readiness (use the existing readiness flag or isReadyToAppend
equivalent) before calling appendBatch, only call
emptyStateViewModel.setEmpty(false) on successful append, and return false on
timeout/no-append so callers can requeue; then update processLogs to re-enqueue
the batch (with optional short backoff) when flushToEditor returns false to
prevent data loss.
- Line 39: The logChannel currently uses Channel.UNLIMITED which can grow
unbounded; change its creation to a bounded channel (e.g., Channel(capacity) or
Channel(Channel.BUFFERED) with a defined onBufferOverflow policy like
DROP_OLDEST or DROP_LATEST) to provide backpressure and avoid OOM during heavy
logging; update any producers that call logChannel.trySend(...) to handle
dropped messages or backpressure (check send/trySend result) and keep the rest
of the UI consumer logic for reading from logChannel unchanged (refer to the
logChannel variable and places that call trySend/send).

… crash

Ensure the editor is attached and laid out before flushing pending output to avoid ArrayIndexOutOfBoundsException.
- Implement Coroutine Channel to process logs off the main thread.
- Add batching logic to reduce UI layout passes and prevent ANRs.
- Add `awaitLayout` to ensure editor readiness, fixing ArrayIndexOutOfBoundsException.
@jatezzz jatezzz force-pushed the fix/ADFA-2593-build-output-crash branch from 3bd91ec to c371b55 Compare January 28, 2026 20:24
@jatezzz jatezzz merged commit 2567365 into stage Jan 29, 2026
2 checks passed
@jatezzz jatezzz deleted the fix/ADFA-2593-build-output-crash branch January 29, 2026 16:41
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.

3 participants