nathanmarz/storm · error · FailedException

Received commit for different transaction attempt

Error message

Received commit for different transaction attempt

What it means

During Trident batch processing, the commit stream delivers a TransactionAttempt that must match the attempt the executor recorded for that transaction id. If the attempt on the commit stream differs from the one stored in _activeBatches, the batch state is inconsistent (e.g. a replay with a new attempt id) and Trident throws FailedException so the batch is replayed.

Solutions

  1. Let the FailedException propagate — Trident will replay the batch with the correct attempt
  2. Verify the spout/emitter are stateless and correctly re-registered attempts after restart
  3. Check MasterBatchCoordinator zk state for stale transaction metadata and ensure only one topology uses the same state location
Defensive patterns

Strategy: try-catch

Try / catch

// Trident worker: FailedException marks batch for replay
try {
  executor.execute(tuple);
} catch (FailedException e) {
  LOG.warn("Commit attempt mismatch; batch will be replayed", e);
  // do not ack; let Trident replay with the correct attempt
}

Prevention

When it happens

Trigger: A commit tuple arrives on MasterBatchCoordinator.COMMIT_STREAM_ID whose TransactionAttempt does not equal the active attempt registered for the same transaction id — typically after topology restarts/replays where the spout re-emits a transaction with a different attempt number.

Common situations: Topology rebalanced or restarted mid-transaction; expired messages causing rebroadcast with a new attempt; misbehaving custom spout emitting mismatched attempts.

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/ddddce9c040e3d7c. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/storm/trident/spout/TridentSpoutExecutor.java:73

        _streamName = streamName;
    }
    
    @Override
    public void prepare(Map conf, TopologyContext context, BatchOutputCollector collector) {
        _emitter = _spout.getEmitter(_txStateId, conf, context);
        _collector = new AddIdCollector(_streamName, collector);
    }

    @Override
    public void execute(BatchInfo info, Tuple input) {
        // there won't be a BatchInfo for the success stream
        TransactionAttempt attempt = (TransactionAttempt) input.getValue(0);
        if(input.getSourceStreamId().equals(MasterBatchCoordinator.COMMIT_STREAM_ID)) {
            if(attempt.equals(_activeBatches.get(attempt.getTransactionId()))) {
                ((ICommitterTridentSpout.Emitter) _emitter).commit(attempt);
                _activeBatches.remove(attempt.getTransactionId());
            } else {
                 throw new FailedException("Received commit for different transaction attempt");
            }
        } else if(input.getSourceStreamId().equals(MasterBatchCoordinator.SUCCESS_STREAM_ID)) {
            // valid to delete before what's been committed since 
            // those batches will never be accessed again
            _activeBatches.headMap(attempt.getTransactionId()).clear();
            _emitter.success(attempt);
        } else {            
            _collector.setBatch(info.batchId);
            _emitter.emitBatch(attempt, input.getValue(1), _collector);
            _activeBatches.put(attempt.getTransactionId(), attempt);
        }
    }

    @Override
    public void cleanup() {
        _emitter.close();
    }

View on GitHub (pinned to cdb116e942)