{"record":{"id":"4bb2cc7dbe70883b","repo":"apache/incubator-seata","slug":"branchtype-must-be-not-null","errorCode":null,"errorMessage":"branchType must be not null","messagePattern":"branchType must be not null","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/seata/core/context/RootContext.java","lineNumber":241,"sourceCode":"        if (inGlobalTransaction()) {\n            BranchType branchType = (BranchType) CONTEXT_HOLDER.get(KEY_BRANCH_TYPE);\n            if (branchType != null) {\n                return branchType;\n            }\n            // Returns the default branch type.\n            return DEFAULT_BRANCH_TYPE != null ? DEFAULT_BRANCH_TYPE : BranchType.AT;\n        }\n        return null;\n    }\n\n    /**\n     * bind branch type\n     *\n     * @param branchType the branch type\n     */\n    public static void bindBranchType(@Nonnull BranchType branchType) {\n        if (branchType == null) {\n            throw new IllegalArgumentException(\"branchType must be not null\");\n        }\n        if (LOGGER.isDebugEnabled()) {\n            LOGGER.debug(\"bind branch type {}\", branchType);\n        }\n\n        CONTEXT_HOLDER.put(KEY_BRANCH_TYPE, branchType);\n    }\n\n    /**\n     * unbind branch type\n     *\n     * @return the previous branch type or null\n     */\n    @Nullable\n    public static BranchType unbindBranchType() {\n        BranchType unbindBranchType = (BranchType) CONTEXT_HOLDER.remove(KEY_BRANCH_TYPE);\n        if (LOGGER.isDebugEnabled()) {\n            LOGGER.debug(\"unbind branch type {}\", unbindBranchType);","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/apache/incubator-seata/blob/e01f97c6db397165050caa6764020410c2c8199a/core/src/main/java/org/apache/seata/core/context/RootContext.java#L223-L259","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Guard the call site: only bind when the extracted value is non-null.","Fix the upstream extraction — if the annotation attribute is optional, choose BranchType.AT explicitly or skip binding.","Update third-party starters/adapters to a version compatible with the @Nonnull contract."],"exampleFix":"// before\nRootContext.bindBranchType(branchType);\n// after\nif (branchType != null) {\n    RootContext.bindBranchType(branchType);\n}","handlingStrategy":"validation","validationCode":"if (branchType != null) {\n    RootContext.bindBranchType(branchType);\n} else {\n    LOG.debug(\"no branch type to bind, skipping\");\n}","typeGuard":"boolean bindable(BranchType t) { return t != null; }","tryCatchPattern":"catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"not null\")) { /* skip binding, keep context intact */ }\n    else throw e;\n}","preventionTips":["Null-check extracted annotation attributes before binding","Always pair bind with unbind in finally to keep thread context clean"],"tags":["null-safety","context","branch-type","programmatic"],"backgroundTag":null,"analyzedSha":"e01f97c6db397165050caa6764020410c2c8199a","analyzedAt":"2026-08-14T10:23:53.097Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}