{"record":{"id":"1877ab7de3659a58","repo":"phalcon/cphalcon","slug":"invalid-module-definition-for-module-modulename-1877ab","errorCode":null,"errorMessage":"Invalid module definition for module '{moduleName}': The module definition object must be a Closure","messagePattern":"Invalid module definition for module '(.+?)': The module definition object must be a Closure","errorType":"exception","errorClass":"Phalcon\\Cli\\Console\\Exceptions\\InvalidModuleDefinition","httpStatus":null,"severity":"error","filePath":"phalcon/Cli/Console.zep","lineNumber":145,"sourceCode":"                    if !class_exists(className, false) {\n                        require_once path;\n                    }\n                }\n\n                let moduleObject = <ModuleDefinitionInterface> this->container->get(className);\n\n                /**\n                 * 'registerAutoloaders' and 'registerServices' are\n                 * automatically called\n                 */\n                moduleObject->registerAutoloaders(this->container);\n                moduleObject->registerServices(this->container);\n            } else {\n                /**\n                 * A module definition object, can be a Closure instance\n                 */\n                if unlikely !(module instanceof Closure) {\n                    throw new InvalidModuleDefinition(\n                        moduleName,\n                        \"The module definition object must be a Closure\"\n                    );\n                }\n\n                let moduleObject = call_user_func_array(\n                    module,\n                    [\n                        this->container\n                    ]\n                );\n            }\n\n            /**\n             * The \"afterStartModule\" event is fired once the module has\n             * started. Unlike Phalcon\\Mvc\\Application - where the return value\n             * is a notification only - Console honors a `false` return and\n             * aborts handling. This divergence is retained for backward","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Cli/Console.zep#L127-L163","documentation":"The other branch of CLI module loading: when the definition is an object (not an array), Phalcon requires it to be a Closure. The closure is invoked with the DI container via call_user_func_array and must return an object implementing the module definition interface (registerAutoloaders/registerServices). Passing any other object — even an already-constructed module instance — throws this.","triggerScenarios":"$console->registerModules(['api' => new \\App\\Api\\Module($logger)]) — a ready-made instance instead of a Closure; also any stdClass or helper object used as the definition.","commonSituations":"Developers instantiate the module class directly because it needs constructor arguments, instead of wrapping construction in a closure or using the className/path array form.","solutions":["Wrap construction in a closure: 'api' => function ($di) { return new \\App\\Api\\Module($di->get('logger')); }","Or switch to the array definition with className/path and let the DI container construct the module"],"exampleFix":"// before\n$console->registerModules([\n    'api' => new \\App\\Api\\Module($logger),\n]);\n\n// after\n$console->registerModules([\n    'api' => function ($di) {\n        return new \\App\\Api\\Module($di->get('logger'));\n    },\n]);","handlingStrategy":"validation","validationCode":"foreach ($modules as $name => $definition) {\n    if (is_object($definition) && !$definition instanceof \\Closure) {\n        throw new InvalidArgumentException(sprintf(\n            'Module \"%s\" object definition must be a Closure, got %s',\n            $name,\n            get_class($definition)\n        ));\n    }\n}","typeGuard":"/**\n * Object module definitions must be Closures; anything else\n * (including module instances) is rejected by Cli\\Console::handle().\n */\nfunction isClosureModuleDefinition($definition): bool\n{\n    return $definition instanceof \\Closure;\n}","tryCatchPattern":"try {\n    $console->handle();\n} catch (\\Phalcon\\Cli\\Console\\Exception\\InvalidModuleDefinition $e) {\n    if (strpos($e->getMessage(), 'Closure') !== false) {\n        // Object definition branch: wrap the instance in a closure instead\n        $stderr->writeln('Wrap object module definitions in a Closure: ' . $e->getMessage());\n    }\n    exit(1);\n}","preventionTips":["Never register a pre-constructed module instance; wrap it in a closure that receives the container","Use the className/path array form when the module has no constructor arguments"],"tags":["phalcon","cli","module","closure","configuration"],"backgroundTag":"invalid-module-definition","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}