apache/incubator-seata · error · IllegalArgumentException

branchType must be not null

Error message

branchType must be not null

What it means

RootContext.bindBranchType is annotated @Nonnull and throws IllegalArgumentException on a null argument. It stores the current branch type into the thread-bound context (CONTEXT_HOLDER); a null would corrupt later getBranchType/unbind logic, so it fails fast.

Source

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

        if (inGlobalTransaction()) {
            BranchType branchType = (BranchType) CONTEXT_HOLDER.get(KEY_BRANCH_TYPE);
            if (branchType != null) {
                return branchType;
            }
            // Returns the default branch type.
            return DEFAULT_BRANCH_TYPE != null ? DEFAULT_BRANCH_TYPE : BranchType.AT;
        }
        return null;
    }

    /**
     * bind branch type
     *
     * @param branchType the branch type
     */
    public static void bindBranchType(@Nonnull BranchType branchType) {
        if (branchType == null) {
            throw new IllegalArgumentException("branchType must be not null");
        }
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("bind branch type {}", branchType);
        }

        CONTEXT_HOLDER.put(KEY_BRANCH_TYPE, branchType);
    }

    /**
     * unbind branch type
     *
     * @return the previous branch type or null
     */
    @Nullable
    public static BranchType unbindBranchType() {
        BranchType unbindBranchType = (BranchType) CONTEXT_HOLDER.remove(KEY_BRANCH_TYPE);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("unbind branch type {}", unbindBranchType);

View on GitHub (pinned to e01f97c6db)

Solutions

  1. Guard the call site: only bind when the extracted value is non-null.
  2. Fix the upstream extraction — if the annotation attribute is optional, choose BranchType.AT explicitly or skip binding.
  3. Update third-party starters/adapters to a version compatible with the @Nonnull contract.

Example fix

// before
RootContext.bindBranchType(branchType);
// after
if (branchType != null) {
    RootContext.bindBranchType(branchType);
}
Defensive patterns

Strategy: validation

Validate before calling

if (branchType != null) {
    RootContext.bindBranchType(branchType);
} else {
    LOG.debug("no branch type to bind, skipping");
}

Type guard

boolean bindable(BranchType t) { return t != null; }

Try / catch

catch (IllegalArgumentException e) {
    if (e.getMessage().contains("not null")) { /* skip binding, keep context intact */ }
    else throw e;
}

Prevention

When it happens

Trigger: Programmatic call bindBranchType(null) — typically an interceptor or framework adapter that extracts a branch type from an annotation/request and passes it through without a null check (e.g. custom SAGA/TCC integration code where the attribute was absent).

Common situations: Custom Seata integration glue, a mirated SDK version where a previously-nullable signature now throws, or interceptors running on endpoints that do not carry the branch-type attribute.

Related errors


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