Skip to content

fix: retry chunk uploads when the error response has a JSON body - #75

Merged
vilenarios merged 4 commits into
masterfrom
fix/chunk-error-body-retry
Oct 17, 2026
Merged

vilenarios merged 4 commits into
masterfrom
fix/chunk-error-body-retry

Conversation

@vilenarios

@vilenarios vilenarios commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

getResponseErrorFromDioRespose threw when Dio had already decoded a JSON error body into a Map. The throw was an Error, not an Exception, so the chunk retry added in 4.0.1 did not run, and the upload stopped after its first chunk attempt.

Changes

  • getResponseErrorFromDioRespose reads the error from a Map, List, String or empty body, and no longer throws.
  • uploadTransaction counts a header the network already has as posted, and sends the chunks:
    • 208 "Transaction already processed.", as before
    • 400 "Transaction is already in the mempool." (pending for more than 10 minutes)
    • 400 "Transaction is already on the weave." (mined, while its anchor is still recent)
  • New uploadTransactionChunks posts a transaction's chunks without posting its header. It covers transactions too old for a re-posted header to be recognised. This is an addition; existing functions are unchanged.
  • The first chunk is sent on its own, and the rest fan out (up to 128) once it is accepted. Until the header reaches the nodes every chunk is rejected and retried, and the gateway forwards each attempt to several peers. Retrying every chunk at once multiplied that traffic for nothing.
  • Version 4.1.0, because of the new API.

Testing

  • test/chunk_upload_retry_test.dart covers:
    • each error body shape
    • a chunk retried after a 400 JSON response
    • a chunks-only upload, which posts no header
    • the header responses for pending, mined and refused transactions
    • a 3-chunk upload whose first chunk is rejected twice, which must send nothing else until that chunk is accepted
  • The parser, retry, "already on the weave" and fan-out tests fail against the code before their fixes.
  • The rest of the suite is unchanged. Two transactions_test.dart cases fail on master too, because they need arweave.net.

Follow-ups, not in this PR

  • An AR.IO gateway's chunk response has no per-peer error strings, so _fatalChunkUploadErrors never matches through a gateway. A truly fatal chunk is retried for about 10 minutes before failing. That is slow, but it is not data loss.
  • lib/src/models/transaction_uploader.dart (the http-package path) is unchanged.

After merge, tag v4.1.0 so ardrive-web can pin it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XxK9v6SqyxtV5g4yaXSkB1

Summary by CodeRabbit

  • New Features
    • Added support for uploading transaction chunks without submitting the transaction header.
  • Bug Fixes
    • Header uploads now succeed when the transaction is already in the mempool or on the weave.
    • Improved error-message handling across response formats, including plain text, JSON, and empty responses.
    • Updated chunk uploads to begin sequentially, then continue with up to 128 concurrent uploads, replacing each completed upload as it finishes.

getResponseErrorFromDioRespose did not handle a response body that Dio had
already decoded from JSON, and threw while reading it. Because the throw was
an Error rather than an Exception, the chunk retry did not run and the
upload stopped after its first chunk attempt.

- read the error from a Map, List, String or empty body without throwing
- tests for each body shape, and for a chunk upload that retries after a
  JSON error response
- version 4.0.3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxK9v6SqyxtV5g4yaXSkB1
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 346d7550-d773-4750-b81c-c035af6c4d2e
📥 Commits

Reviewing files that changed from the base of the PR and between e399497 and 1573dae.

📒 Files selected for processing: 3
  • lib/src/streams/transaction_uploader.dart
  • pubspec.yaml
  • test/chunk_upload_retry_test.dart

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The Dio response-error utility now handles response bodies by runtime type. Transaction uploads accept specified already-processed header responses, use revised chunk scheduling, and support chunk-only uploads. Tests cover response decoding and upload behavior. The package version changes to 4.1.0.

Changes: Dio response decoding

Layer / File(s) Summary
Response body handling
lib/src/utils.dart, test/chunk_upload_retry_test.dart
The utility extracts string errors and nested string data, preserves unparseable strings, JSON-encodes other non-null values, and returns an empty string for null. Tests cover decoded and string-encoded JSON, legacy nested errors, gateway results, plain text, and empty bodies.

Transaction chunk uploads

Layer / File(s) Summary
Header handling and chunk-only uploads
lib/src/streams/transaction_uploader.dart, test/chunk_upload_retry_test.dart, pubspec.yaml
HTTP 400 header responses containing “already in the mempool” or “already on the weave” are accepted. uploadTransactionChunks uploads chunks without posting the header. Tests cover accepted and unrelated rejected header responses, and chunk-only uploads. The package version changes to 4.1.0.
Chunk scheduling and retry
lib/src/streams/transaction_uploader.dart, test/chunk_upload_retry_test.dart
The uploader sends the first chunk alone, then starts up to 128 uploads and starts one replacement upload for each later completion. Tests cover retrying rejected chunks and upload progress.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: thiagocarvalhodev

Merge Risk: ⚪ Minimal · up to 1573d

The inspected upload and retry paths show no outstanding issue requiring a fix before merge.

Pre-merge checks: Passed 5
Check name Status Explanation
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
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.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title accurately identifies the primary change: fixing chunk-upload retries when Dio returns an error response with a JSON body. It does not mention the additional chunk-only upload and already-ac…
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (3 skipped: 3 unsupported.)

Full details: Title check

Explanation

The title accurately identifies the primary change: fixing chunk-upload retries when Dio returns an error response with a JSON body. It does not mention the additional chunk-only upload and already-accepted-header behavior, but the title need not cover every change.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

vilenarios and others added 2 commits October 16, 2026 09:04
uploadTransactionChunks posts only the chunks, for a transaction the network
already has. Posting the header of a mined transaction again is refused, so a
caller resuming an upload needs a way to send the chunks on their own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxK9v6SqyxtV5g4yaXSkB1
…weave

A node answers 400 "Transaction is already on the weave." to the header of a
mined transaction. uploadTransaction treated that as a failed upload and sent
no chunks, so resending a transaction that had just been mined failed even
though only its chunks were missing. That answer now counts as a posted
header, as 208 for a pending one already did, and the chunks are sent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxK9v6SqyxtV5g4yaXSkB1
From review of the chunk retry fix.

- a node answers 400 "Transaction is already in the mempool." to a header it
  has had pending for more than ten minutes, after its 208 lapses; that now
  counts as a posted header too, so a resent upload posts its chunks
- the first chunk is sent alone, and the rest fan out once it is accepted.
  Until the header reaches the nodes every chunk is rejected and retried, and
  the gateway posts each attempt to several peers, so retrying all of them
  at once multiplied that traffic for nothing
- doc comments say how long a node recognises a resent header
- version 4.1.0, since uploadTransactionChunks is new API

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxK9v6SqyxtV5g4yaXSkB1
vilenarios added a commit to ardriveapp/ardrive-web that referenced this pull request Oct 16, 2026
Moves the pin to the head of ardriveapp/arweave-dart#75 after review: a
header pending for more than ten minutes now counts as posted, and the first
chunk is sent alone before the rest fan out. The pin moves to v4.1.0 once
that is tagged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxK9v6SqyxtV5g4yaXSkB1
@vilenarios
vilenarios merged commit c5afb66 into master Oct 17, 2026
4 checks passed
@vilenarios
vilenarios deleted the fix/chunk-error-body-retry branch October 17, 2026 13:42
vilenarios added a commit to ardriveapp/ardrive-web that referenced this pull request Oct 17, 2026
ardriveapp/arweave-dart#75 is merged and tagged v4.1.0 (c5afb66), so the
pins move from the reviewed commit 1573dae to the tag. The tag's tree is
the same as that commit's; it adds only the merge commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZiqyGae4T1gJLGGB29pR9
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.

1 participant