Skip to content

Handle every send status in submitTx and poll until the time bound - #2977

Open
stellar-triage-bot[bot] wants to merge 5 commits into
mainfrom
docs-agent/2962-submit-tx-send-statuses
Open

stellar-triage-bot[bot] wants to merge 5 commits into
mainfrom
docs-agent/2962-submit-tx-send-statuses

Conversation

@stellar-triage-bot

@stellar-triage-bot stellar-triage-bot Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

🤖 Automated message from the Stellar Triage Bot.

Closes #2962

Working this because @oceans404 added bot:take. This PR rewrites the shared submitTx helper so that it handles every send status and never reports NOT_FOUND as a failure.

What changes

  • New table: what each sendTransaction status means and what to do.
  • TRY_AGAIN_LATER: the helper waits 2 s and sends the same signed transaction again, until maxTime passes.
  • DUPLICATE: treated like PENDING. The helper polls for the result.
  • ERROR: the helper calls getTransaction first. A resend of an applied transaction returns TRY_AGAIN_LATER for about 10 ledgers, then ERROR (txBAD_SEQ), so this keeps a second send from throwing.
  • Polling: runs until SUCCESS or FAILED, or until a ledger closes after maxTime. Only then does it throw "expired".
  • New warning: pollTransaction() returns the last NOT_FOUND when its attempts run out (30 by default).
  • The restoreContract snippets in restore-contract-js.mdx and state-archival.mdx now call setTimeout(30). build() and the new maxTime guard both need it.

Sources

  • @stellar/stellar-sdk v17.4.0: SendTransactionStatus (rpc/api.ts:515), pollTransaction (rpc/server.ts:1240-1260), default attempts DEFAULT_GET_TRANSACTION_TIMEOUT = 30 (rpc/server.ts:114), GetTransactionResponse.latestLedgerCloseTime (rpc/api.ts:104).
  • stellar-core TransactionQueue.cpp: DUPLICATE means the same transaction is already queued. TRY_AGAIN_LATER means another transaction from the source is queued, or the transaction hash is banned. removeApplied bans an applied transaction for TRANSACTION_QUEUE_BAN_LEDGERS = 10 ledgers (HerderImpl.cpp). After that, an applied transaction fails validation with txBAD_SEQ.
  • Live testnet getTransaction: latestLedgerCloseTime is a string, so the helper wraps it in Number().
  • @oceans404 ran submitTx on SDK 17.4.0 against a local network: normal send, resend of a landed transaction, TRY_AGAIN_LATER, expiry, on-chain failure and a missing time bound all behave as the page says.

Checks

  • pnpm is not available in this environment, so pnpm format:mdx, pnpm check and pnpm check:links did not run here. CI runs the checks job.
  • The return type stays Api.GetTransactionResponse. Callers in restore-data-js.mdx and state-archival.mdx compare resp.status with SUCCESS, and a narrower type would break them.

Notes for reviewers

TRY_AGAIN_LATER now resends the same signed transaction, DUPLICATE is treated as pending, and ERROR checks getTransaction first so a resend of an applied transaction does not throw. Polling runs until a ledger closes past maxTime instead of five attempts, so NOT_FOUND is never reported as a failure. Adds a status table and a pollTransaction warning.
@mintlify

mintlify Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
stellar-docs 🟢 Ready View Preview Nov 3, 2026, 1:24 AM

@stellar-triage-bot stellar-triage-bot Bot added the bot:ready-to-merge Bot verified and approved; waiting for a maintainer to merge label Nov 2, 2026
@stellar-triage-bot

Copy link
Copy Markdown
Contributor Author

🤖 Automated message from the Stellar Triage Bot.

Reviewing my own PR for #2962, which @oceans404 called me in on with bot:take.

  • Verified: the statuses and polling match SDK v17.4.0 and the RPC spec. The preview renders, and all checks pass.
  • Fixed: the warning said pollTransaction stops after 5 attempts by default. The SDK default is 30.

Ready to merge. PR #2933 edits the same lines, so the second one to merge needs a small conflict fix.

@ElliotFriend ElliotFriend left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the most useful PR in the batch, thanks. The status handling checks out against v17.4.0. Two things:

  1. Rebase needed. #2933 merged and also edited submitTx in submit-transaction-wait-js.mdx (it fixed tmpStatus/status with a finalStatus rename). Your rewrite supersedes that hunk, so resolve the conflict in favor of this PR's helper. #2933 also added .setTimeout(30) to the restore transactions in restore-data-js.mdx and state-archival.mdx, so your maxTime guard is satisfied there now.
  2. Wording, line 10. "Only ERROR means that the network rejected the transaction" reads as contradicting the TRY_AGAIN_LATER row, which says the network "did not accept" it. Please reword one of them, e.g. "Only ERROR is a final rejection."

Optional, but related: restore-contract-js.mdx builds its transaction without setTimeout, so it throws at build() today and would also trip the new guard. Happy for that to be a follow-up issue instead.

@ElliotFriend

Copy link
Copy Markdown
Contributor

/triage

oceans404 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Tested submitTx on SDK 17.4.0 against a local network. A normal send, resending a transaction that already landed, TRY_AGAIN_LATER, an expired transaction, an on-chain failure and a missing time bound all behave the way the page says.

One nit on the status table: resending a transaction that's already in a ledger didn't return ERROR (txBAD_SEQ) right away. It returned TRY_AGAIN_LATER for about 9 ledgers first, and only then ERROR. The helper still handles it (it keeps resending, then finds the result), but the TRY_AGAIN_LATER and ERROR rows could mention this, so readers don't assume TRY_AGAIN_LATER always means another transaction is still waiting.

…t-tx-send-statuses

# Conflicts:
#	docs/build/guides/transactions/submit-transaction-wait-js.mdx
…nippets

Only ERROR is now called a final rejection. The TRY_AGAIN_LATER and ERROR rows say that a resend of an applied transaction returns TRY_AGAIN_LATER for about 10 ledgers before ERROR (txBAD_SEQ). The restoreContract snippets in restore-contract-js.mdx and state-archival.mdx now call setTimeout(30), which build() and submitTx both require.
@stellar-triage-bot

Copy link
Copy Markdown
Contributor Author

🤖 Automated message from the Stellar Triage Bot.

Back on this because @ElliotFriend asked with /triage and requested changes.

  • Merged main. I kept this PR's submitTx, which replaces the Fix signing and submission in the archival and simulation examples #2933 hunk.
  • Line 10 now says "Only ERROR is a final rejection."
  • @oceans404, thanks for the test. Confirmed in stellar-core: an applied transaction is banned for 10 ledgers. The TRY_AGAIN_LATER and ERROR rows now say so.
  • Added setTimeout(30) to restoreContract in restore-contract-js.mdx and state-archival.mdx.

Ready to merge. @ElliotFriend, your change request is still open, so only you can clear it.

This branch was successfully deployed

1 active deployment
staging — 8751edb7 Deployed Nov 3, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:ready-to-merge Bot verified and approved; waiting for a maintainer to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Submit and wait (JS): handle TRY_AGAIN_LATER and DUPLICATE, and don't treat a short poll as failure

2 participants