{"record":{"id":"8a3bf2cfa3a8383c","repo":"apache/incubator-seata","slug":"non-businessactioncontext-parameter-should-use-ann","errorCode":null,"errorMessage":"non-BusinessActionContext parameter should use annotation BusinessActionContextParameter","messagePattern":"non-BusinessActionContext parameter should use annotation BusinessActionContextParameter","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"compatible/src/main/java/io/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java","lineNumber":110,"sourceCode":"        String[] keys = new String[parameterAnnotations.length];\n        /*\n         * get parameter's key\n         * if method's parameter list is like\n         * (BusinessActionContext, @BusinessActionContextParameter(\"a\") A a, @BusinessActionContextParameter(\"b\") B b)\n         * the keys will be [null, a, b]\n         */\n        for (int i = 0; i < parameterAnnotations.length; i++) {\n            for (int j = 0; j < parameterAnnotations[i].length; j++) {\n                if (parameterAnnotations[i][j] instanceof BusinessActionContextParameter) {\n                    BusinessActionContextParameter param = (BusinessActionContextParameter) parameterAnnotations[i][j];\n                    String key =\n                            io.seata.integration.tx.api.interceptor.ActionContextUtil.getParamNameFromAnnotation(param);\n                    keys[i] = key;\n                    break;\n                }\n            }\n            if (keys[i] == null && !(argsClasses[i].equals(BusinessActionContext.class))) {\n                throw new IllegalArgumentException(\"non-BusinessActionContext parameter should use annotation \"\n                        + \"BusinessActionContextParameter\");\n            }\n        }\n        return keys;\n    }\n}\n","sourceCodeStart":92,"sourceCodeEnd":117,"githubUrl":"https://github.com/apache/incubator-seata/blob/e01f97c6db397165050caa6764020410c2c8199a/compatible/src/main/java/io/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java#L92-L117","documentation":"Thrown by the compatible TCC parser while validating a TCC method signature: every parameter that is not a BusinessActionContext must be annotated with @BusinessActionContextParameter. This is how the parser knows which parameters to propagate into the rollback/commit context; unannotated business parameters make branch retry impossible to bind correctly.","triggerScenarios":"A @TwoPhaseBusinessAction prepare/commit/rollback method has a parameter that is neither BusinessActionContext nor annotated @BusinessActionContextParameter. The parser walks parameterAnnotations and argsClasses and throws on the first such parameter.","commonSituations":"Adding a new parameter to a TCC method and forgetting the annotation; migrating plain interfaces to TCC; thinking the annotation is optional; version upgrades re-enabling strict parsing that was previously lenient.","solutions":["Annotate every non-BusinessActionContext parameter with @BusinessActionContextParameter(\"paramName\").","Ensure the lone BusinessActionContext parameter (if any) is exactly of type BusinessActionContext — the parser exempts only that type.","Remove extraneous unpropagated parameters from the TCC method signature."],"exampleFix":"// before\n@TwoPhaseBusinessAction(name = \"orderTcc\", commitMethod = \"commit\", rollbackMethod = \"rollback\")\npublic boolean prepare(BusinessActionContext ctx, Long orderId, String note) { ... }\n\n// after\n@TwoPhaseBusinessAction(name = \"orderTcc\", commitMethod = \"commit\", rollbackMethod = \"rollback\")\npublic boolean prepare(BusinessActionContext ctx,\n                      @BusinessActionContextParameter(\"orderId\") Long orderId,\n                      @BusinessActionContextParameter(\"note\") String note) { ... }","handlingStrategy":"validation","validationCode":"for (java.lang.reflect.Parameter p : method.getParameters()) {\n    boolean isCtx = p.getType().equals(BusinessActionContext.class);\n    boolean annotated = p.isAnnotationPresent(BusinessActionContextParameter.class);\n    if (!isCtx && !annotated) {\n        throw new IllegalStateException(\"parameter '\" + p.getName()\n            + \"' of \" + method + \" needs @BusinessActionContextParameter\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    // bean scan / interceptor parse at startup\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"BusinessActionContextParameter\")) {\n        throw new ConfigurationException(\"TCC method signature invalid: annotate non-context parameters\", e);\n    }\n    throw e;\n}","preventionTips":["Annotate every business parameter of TCC methods with @BusinessActionContextParameter(\"name\").","Only the BusinessActionContext-typed parameter may go unannotated.","Cover TCC interfaces with a signature-validation test so regressions fail at build time."],"tags":["tcc","annotation","validation","interceptor"],"backgroundTag":null,"analyzedSha":"e01f97c6db397165050caa6764020410c2c8199a","analyzedAt":"2026-08-14T10:23:53.097Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}