{"record":{"id":"eadcc50b1298c6df","repo":"YunaiV/ruoyi-vue-pro","slug":"invalid-command-interceptor-chain-configuration","errorCode":null,"errorMessage":"invalid command interceptor chain configuration: {}","messagePattern":"invalid command interceptor chain configuration: (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"critical","filePath":"sql/dm/flowable-patch/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java","lineNumber":665,"sourceCode":"\n    public abstract String getEngineCfgKey();\n\n    public abstract String getEngineScopeType();\n\n    public List<CommandInterceptor> getAdditionalDefaultCommandInterceptors() {\n        return null;\n    }\n\n    public void initCommandExecutor() {\n        if (commandExecutor == null) {\n            CommandInterceptor first = initInterceptorChain(commandInterceptors);\n            commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);\n        }\n    }\n\n    public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {\n        if (chain == null || chain.isEmpty()) {\n            throw new FlowableException(\"invalid command interceptor chain configuration: \" + chain);\n        }\n        for (int i = 0; i < chain.size() - 1; i++) {\n            chain.get(i).setNext(chain.get(i + 1));\n        }\n        return chain.get(0);\n    }\n\n    public abstract CommandInterceptor createTransactionInterceptor();\n\n\n    public void initBeans() {\n        if (beans == null) {\n            beans = new HashMap<>();\n        }\n    }\n\n    // id generator\n    // /////////////////////////////////////////////////////////////","sourceCodeStart":647,"sourceCodeEnd":683,"githubUrl":"https://github.com/YunaiV/ruoyi-vue-pro/blob/0418084e222612af2fc1141f566af454f9236ab1/sql/dm/flowable-patch/src/main/java/org/flowable/common/engine/impl/AbstractEngineConfiguration.java#L647-L683","documentation":"Flowable's initInterceptorChain requires a non-empty list of CommandInterceptors to wire into a linked list (each.setNext(next)). If commandInterceptors is null or empty the chain cannot be built and there is no first interceptor for the CommandExecutor, so it throws FlowableException. This is almost always a misconfiguration of the interceptor stack.","triggerScenarios":"A custom engine configuration overrides getCommandInterceptors()/createCommandInterceptors() and returns null or an empty list; a config subclass forgets to call super and to include the default interceptors; programmatic config that clears commandInterceptors.","commonSituations":"Customizing the Flowable command stack (adding metrics/audit interceptors) but returning an empty list by mistake; subclassing a process engine config and breaking the interceptor chain.","solutions":["Ensure getCommandInterceptors() returns a non-empty list that includes the required log interceptor and ends with the transaction interceptor.","When subclassing, build on super.getCommandInterceptors() rather than replacing it entirely.","If configuring programmatically, call setCommandInterceptors() with a populated list before buildProcessEngine()."],"exampleFix":"// before\n@Override public List<CommandInterceptor> getCommandInterceptors() { return Collections.emptyList(); }\n// after\n@Override public List<CommandInterceptor> getCommandInterceptors() {\n    List<CommandInterceptor> list = new ArrayList<>(super.getCommandInterceptors());\n    list.add(0, new MyAuditInterceptor());\n    return list;\n}","handlingStrategy":"validation","validationCode":"List<CommandInterceptor> is = cfg.getCommandInterceptors();\nif (is == null || is.isEmpty()) throw new IllegalStateException(\"commandInterceptors must be non-empty\");","typeGuard":"static boolean hasValidInterceptorChain(List<CommandInterceptor> c) { return c != null && !c.isEmpty(); }","tryCatchPattern":"try { engine = cfg.buildProcessEngine(); }\ncatch (FlowableException e) { if (e.getMessage().contains(\"command interceptor chain\")) { /* fix config */ } throw e; }","preventionTips":["Subclasses must build on super.getCommandInterceptors()","Never set commandInterceptors to null or empty","Unit-test custom configs that buildProcessEngine() successfully"],"tags":["flowable","command-interceptor","configuration","engine-init"],"backgroundTag":null,"analyzedSha":"0418084e222612af2fc1141f566af454f9236ab1","analyzedAt":"2026-08-14T00:56:18.412Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}