Skip to main content
A blockchain can reorganize, or reorg, when blocks on the current chain are replaced by blocks from another branch. Data derived from the replaced blocks must also be removed or recalculated. Portal can detect this when a client resumes a standard stream with:
  • fromBlock: the next block the client wants
  • parentBlockHash: the hash of the block immediately before fromBlock, meaning the last block the client already trusts
Portal compares the hash with the parent of fromBlock on the current chain. If the hashes match, the stream starts normally. If they do not match, the chain changed between the client’s last processed block and fromBlock. The client cannot safely resume from this block, and Portal returns HTTP 409 Conflict.
Send parentBlockHash whenever you resume a standard stream. A reorg can happen on any chain; you cannot prevent conflicts, only detect them. A client that omits parentBlockHash silently processes blocks from a forked chain after a reorg, with no signal that anything is wrong.
For example, after this reorg the block N+1 that the client may have already processed is no longer on the current chain: If the client resumes with fromBlock = N+2 and parentBlockHash = hash(N+1), Portal sees that N+1 is not the parent of the next block on the current chain and reports the conflict.

Conflict response body

  • error is the envelope that every failing Portal response carries. Match on error.code (base_block_mismatch here) rather than on error.message, which is prose and can change. See Error handling for the full contract.
  • previousBlocks is an array of { number, hash } pairs from the current chain at and below the conflict point. It stays at the top level, beside error.
  • The array length is arbitrary, but the array always contains at least the parent of the requested fromBlock.
  • The array is in ascending order: the lowest block number comes first, and the last entry is the most recent block at or below the conflict point.

Recovering from a conflict

  1. Walk previousBlocks from its last entry (the most recent block) and look for a block whose (number, hash) pair you have already processed and stored.
  2. If you find a shared block at height K, remove data derived from later blocks and resume the stream with fromBlock = K + 1 and parentBlockHash = hash(K).
  3. If no block in previousBlocks matches your records, the divergence is deeper than the returned slice. Open a new stream with a fromBlock further in the past and repeat the search. Pass parentBlockHash on every retry as well, so that each conflict narrows the search instead of repeating it.
Portal never says to rewind to one exact block. It returns a slice of the current chain, and the client compares that slice against its own state. The request examples and chain-specific recovery walkthroughs are in the API guides:

EVM fork recovery

Handle HTTP 409 while reading recent EVM blocks.

Solana fork recovery

Handle HTTP 409 while reading recent Solana blocks.
If recent blocks are not required, use the finalized stream instead. Finalized data does not reorganize, so a 409 from the finalized stream only means the stored hash is stale, for example carried over from an unfinalized block. The recovery procedure is the same.