Skip to content

Web host: createTransaction fails with 'subscription dropped' after one refused chainHead re-follow; retry within the call and report chain-unavailable distinctly #1235

Description

@ReinhardHatko

Summary

On the dotli web host (paseo.li, release 0.9.2 on 2026-10-02, @parity/truapi-host 0.23.0), a
product's createTransaction failed with:

createTransaction failed: Unknown: cannot select a metadata block: Cannot construct OnlineClientAtBlock:
cannot get the current block: Backend error: RPC error: RPC error: subscription dropped.

The same signer's next attempt, 5 minutes later, built, signed and included the transaction.

Three things combine:

  1. A single refused re-follow ends the core's Subxt chainHead follow for good, and the
    transaction being built fails with it.
  2. The core rebuilds the connection only on the next call, so the failing call itself is never
    retried.
  3. The error reaches the product as Unknown. The core classifies it as chain-unavailable,
    but nothing on the wire tells the product it is retryable.

Seen in Coffer, a multisig treasury product, on coff3r.paseo.li. The product account's first
approve_as_multi failed this way about 4 s after Coffer shared the proposal off-chain. Coffer then
withdrew the proposal, and the user had to propose again.

Where (at @parity/truapi-host@0.23.0, 37e2d9f)

  • rust/crates/truapi/src/host_internal/extrinsic.rs:332. A failure to build
    OnlineClientAtBlock becomes LocalTransactionError::ChainUnavailable("cannot select a metadata block: …"). For a product account the web host builds the transaction locally
    (pairing_host.rs).
  • rust/crates/truapi/src/runtime.rs:1083-1085. AuthorityError::Unavailable and
    AuthorityError::Unknown both map to v01::HostCreateTransactionError::Unknown { reason }.
  • rust/crates/truapi/src/chain_runtime.rs:1018-1036.
    • The Subxt driver's errors are logged only at debug (chainHead backend error=…), so the
      cause never reaches a web console.
    • When the driver ends, the cached Subxt bundle is invalidated so that the next caller rebuilds
      it. That is why the later attempt succeeded.
  • Subxt 0.50.3.
    • RpcError::SubscriptionDropped is produced by Subxt itself, in
      ChainHeadBackend::latest_finalized_block_ref, when the follow stream ends before an
      initialized event.
    • The follow stream stops for good on any re-follow or stream error other than "disconnected,
      will reconnect" (follow_stream.rs).

The dotli side

dotli's core chain connection (packages/ui/src/host-callbacks/Chain.ts) answers a follow during a
chain or frame halt with a "chain halted" error while its redial gate is shut. The gate stays shut
1 s after a frame halt and backs off to 30 s (redial-gate.ts). The gate is written for a client
that re-follows by itself (redial-gate.ts:6: "papi client re-follows every 250 ms"). Subxt does
not, so one refused re-follow is final.

Not determined:

  • whether this case was a chain halt, a frame halt, or a light-client stop followed by a refused
    re-follow;
  • which backend the user ran: smoldot, the default, or the RPC gateway.

dotli logs halts only in debug builds.

Proposed changes

  1. Retry inside createTransaction. When building the client fails because the follow
    ended (SubscriptionDropped, or a backend whose driver has exited), rebuild the Subxt bundle
    and retry within the call, with a short backoff that outlasts dotli's 1 s redial gate. Nothing
    has been signed or broadcast at that point, so a retry is safe.
  2. Report chain-unavailable as its own wire error. Add a HostCreateTransactionError variant
    (or equivalent) for chain-unavailable instead of folding it into Unknown. A product can then
    retry on that variant alone. Today the only way is matching the reason string.
  3. Log the backend error above debug. Then the console shows why the follow ended.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions