apache/incubator-seata · error · IllegalStateException

Never BEGIN on a RELOADED GlobalTransaction.

Error message

Never BEGIN on a RELOADED GlobalTransaction. 

What it means

GlobalTransactionContext.reload(xid) returns an anonymous DefaultGlobalTransaction whose begin() is hard-wired to throw IllegalStateException, because a reloaded transaction represents a global transaction that has already begun on another JVM/role — it exists only to drive commit(), rollback(), getStatusReport() etc. on an existing XID. Calling begin() on it is a programming error, not a transient failure.

Source

Thrown at compatible/src/main/java/io/seata/tm/api/GlobalTransactionContext.java:77

        GlobalTransaction tx = getCurrent();
        if (tx == null) {
            return createNew();
        }
        return tx;
    }

    /**
     * Reload GlobalTransaction instance according to the given XID
     *
     * @param xid the xid
     * @return reloaded transaction instance.
     * @throws TransactionException the transaction exception
     */
    public static GlobalTransaction reload(String xid) throws TransactionException {
        return new DefaultGlobalTransaction(xid, GlobalStatus.UnKnown, GlobalTransactionRole.Launcher) {
            @Override
            public void begin(int timeout, String name) throws TransactionException {
                throw new IllegalStateException("Never BEGIN on a RELOADED GlobalTransaction. ");
            }
        };
    }
}

View on GitHub (pinned to e01f97c6db)

Solutions

  1. Remove the begin() call on the reloaded instance — participants should propagate the XID (RootContext.bind(xid)) and register branches, not begin.
  2. If you genuinely need to start a new global transaction, use GlobalTransactionContext.getCurrentOrCreate().begin(...) or the @GlobalTransactional annotation instead of reload().
  3. Use reload(xid) only for commit/rollback/status operations on an existing transaction (e.g. a console/admin job forcing rollback by XID).

Example fix

// before
 GlobalTransaction tx = GlobalTransactionContext.reload(xid);
 tx.begin(60000, "order-flow"); // IllegalStateException

// after (participant side: propagate XID, do branch work)
 RootContext.bind(xid);
 // ... business SQL, branch registers with TC ...
 RootContext.unbind();

// after (launcher side: start a new global transaction)
 GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
 tx.begin(60000, "order-flow");
Defensive patterns

Strategy: type-guard

Validate before calling

// A reloaded transaction may never begin — check role/origin before calling lifecycle methods
GlobalTransaction tx = GlobalTransactionContext.reload(xid);
// reloaded instances are Launcher-role handles over an existing XID:
// only commit()/rollback()/getStatus()/globalReport() are valid

Type guard

// Guard: only a newly created/current transaction may begin()
boolean canBegin = (tx.getClass() != GlobalTransactionContext.reload(xid).getClass());
// simpler: track origin yourself
boolean isReloaded = xidProvidedExternally; // XID came from header/MQ
if (!isReloaded) {
    tx.begin(timeout, name);
}

Try / catch

try {
    tx.begin(timeout, name);
} catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().contains("RELOADED")) {
        throw new IllegalStateException("XID " + xid + " already began elsewhere; "
            + "bind it via RootContext.bind(xid) instead of begin()", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Code that fetches a transaction handle via GlobalTransactionContext.reload(xid) (e.g. after receiving an XID in an MQ message or HTTP header) and then calls begin(timeout, name) on it before doing branch work, instead of using getCurrent()/.createNew() or just registering as a participant.

Common situations: Developers porting code from RootContext/TransactionalTemplate patterns and assuming every GlobalTransaction can begin; saga/messaging flows where the XID is propagated and the receiver mistakenly tries to (re)open it; copy-paste of the launcher template into a participant service.

Related errors


AI-assisted analysis of apache/incubator-seata@e01f97c6db (2026-08-14). Data as JSON: /api/errors/de084198c2122197. Report an issue: GitHub.