nathanmarz/storm · error · IllegalStateException

Trying to initialize transaction for which there should be…

Error message

Trying to initialize transaction for which there should be a previous state

What it means

RotatingTransactionalState.getState() in strict-order mode asserts that a transactional state entry exists only if the requested txid is the very first (INIT_TXID). If no previous txid state exists and the txid is not INIT_TXID, the state store is inconsistent (state was lost or never initialized), so it throws IllegalStateException.

Solutions

  1. Restore or rebuild the transactional state store so the previous transaction's state exists before this txid
  2. If the state is genuinely gone and you accept data replay, wipe the coordinator state to restart from INIT_TXID cleanly
  3. Run with _strictOrder=false (non-strict rotating state) if strict ordering is not required for your spout

Example fix

// before
state.getStateOrCreate(BigInteger.valueOf(nextTxid)); // no prior state stored
// after
if (txid.equals(TransactionalSpoutCoordinator.INIT_TXID) || hasPreviousState(txid)) {
    state.getStateOrCreate(txid);
}
Defensive patterns

Strategy: validation

Validate before calling

if (strictOrder && txid.compareTo(TransactionalSpoutCoordinator.INIT_TXID) != 0 && state.hasNoPreviousState()) {
    LOG.error("Transactional state missing for txid {} ; restore state store before initializing", txid);
    return false;
}

Type guard

boolean hasRequiredPrevState(RotatingTransactionalState s, BigInteger txid) {
    return txid.equals(TransactionalSpoutCoordinator.INIT_TXID) || s.hasPreviousState();
}

Try / catch

try {
    state.getStateOrCreate(txid);
} catch (IllegalStateException e) {
    LOG.error("Transactional state chain broken at txid " + txid, e);
    throw new FailedException("State store inconsistent; fail and reinit coordinator", e);
}

Prevention

When it happens

Trigger: Calling getStateOrCreate(txid) (which calls getState) with _strictOrder=true when the internal prevMap is empty and txid != TransactionalSpoutCoordinator.INIT_TXID.

Common situations: Corrupted or wiped transactional state in ZooKeeper/Store after disaster recovery; restoring a topology against an old/broken state directory; manually deleting coordinator state; clock/zookeeper metadata loss during failover of a transactional spout.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12). Data as JSON: /api/errors/037da3f38b57c91a. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/transactional/state/RotatingTransactionalState.java:80

    public void removeState(BigInteger txid) {
        if(_curr.containsKey(txid)) {
            _curr.remove(txid);
            _state.delete(txPath(txid));
        }
    }
    
    public Object getState(BigInteger txid, StateInitializer init) {
        if(!_curr.containsKey(txid)) {
            SortedMap<BigInteger, Object> prevMap = _curr.headMap(txid);
            SortedMap<BigInteger, Object> afterMap = _curr.tailMap(txid);            
            
            BigInteger prev = null;
            if(!prevMap.isEmpty()) prev = prevMap.lastKey();
            
            if(_strictOrder) {
                if(prev==null && !txid.equals(TransactionalSpoutCoordinator.INIT_TXID)) {
                    throw new IllegalStateException("Trying to initialize transaction for which there should be a previous state");
                }
                if(prev!=null && !prev.equals(txid.subtract(BigInteger.ONE))) {
                    throw new IllegalStateException("Expecting previous txid state to be the previous transaction");
                }
                if(!afterMap.isEmpty()) {
                    throw new IllegalStateException("Expecting tx state to be initialized in strict order but there are txids after that have state");                
                }                
            }
            
            
            Object data;
            if(afterMap.isEmpty()) {
                Object prevData;
                if(prev!=null) {
                    prevData = _curr.get(prev);
                } else {
                    prevData = null;
                }

View on GitHub (pinned to cdb116e942)