apache/incubator-seata · error · IllegalArgumentException

The default branch type must be AT or XA. the value of the…

Error message

The default branch type must be AT or XA. the value of the argument is: {defaultBranchType}

What it means

RootContext.setDefaultBranchType rejects any BranchType other than AT or XA. The default branch type is what getBranchType() falls back to when a binding is absent, and only resource-managed branch modes (AT/XA) are valid defaults — TCC and SAGA are always explicitly bound by their interceptors, so they cannot be defaults.

Solutions

  1. Use only AT or XA for the default branch type: seata.client.default-branch-type=at (or xa).
  2. For TCC/SAGA participation, let the @TwoPhaseBusiness/@GlobalTransactional-type annotations and interceptors bind the branch type explicitly; do not set it as default.
  3. Remove custom calls to setDefaultBranchType with non-AT/XA values.

Example fix

# before
seata.client.default-branch-type=tcc
# after
seata.client.default-branch-type=xa
Defensive patterns

Strategy: validation

Validate before calling

BranchType t = BranchType.get(cfgValue);
if (t != BranchType.AT && t != BranchType.XA) {
    throw new ConfigException("default-branch-type only allows AT or XA, got: " + cfgValue);
}

Type guard

boolean isValidDefault(BranchType t) { return t == BranchType.AT || t == BranchType.XA; }

Prevention

When it happens

Trigger: Calling RootContext.setDefaultBranchType(BranchType.TCC) or (SAGA) programmatically, or configuring the client default branch type property as 'TCC'/'SAGA' which is read at startup and pushed into this method.

Common situations: Team sets seata.client.default-branch-type=tcc believing it will make @TwoPhaseBusiness methods behave like a default, or migrates a config where branch type semantics were misunderstood; also custom bootstrap code that copies an explicit bind into the default.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/apache/seata/core/context/RootContext.java:98

     */
    public static final String HIDDEN_KEY_BRANCH_TYPE = Constants.HIDE_KEY_PREFIX_CHAR + KEY_BRANCH_TYPE;

    /**
     * The constant KEY_GLOBAL_LOCK_FLAG, VALUE_GLOBAL_LOCK_FLAG
     */
    public static final String KEY_GLOBAL_LOCK_FLAG = "TX_LOCK";

    public static final Boolean VALUE_GLOBAL_LOCK_FLAG = true;

    private static ContextCore CONTEXT_HOLDER = ContextCoreLoader.load();

    private static BranchType DEFAULT_BRANCH_TYPE;

    public static final String KEY_COMBINE_TRANSACTION_FLAG = "TX_COMBINE";

    public static void setDefaultBranchType(BranchType defaultBranchType) {
        if (defaultBranchType != AT && defaultBranchType != XA) {
            throw new IllegalArgumentException("The default branch type must be " + AT + " or " + XA + "."
                    + " the value of the argument is: " + defaultBranchType);
        }
        if (DEFAULT_BRANCH_TYPE != null && DEFAULT_BRANCH_TYPE != defaultBranchType && LOGGER.isWarnEnabled()) {
            LOGGER.warn(
                    "The `{}.DEFAULT_BRANCH_TYPE` has been set repeatedly. The value changes from {} to {}",
                    RootContext.class.getSimpleName(),
                    DEFAULT_BRANCH_TYPE,
                    defaultBranchType);
        }
        DEFAULT_BRANCH_TYPE = defaultBranchType;
    }

    /**
     * Gets xid.
     *
     * @return the xid
     */
    @Nullable

View on GitHub (pinned to e01f97c6db)