{"record":{"id":"804b38ae6666eb90","repo":"octobercms/october","slug":"vue-component-class-must-be-a-descendant-of-backen","errorCode":null,"errorMessage":"Vue component class must be a descendant of Backend\\Classes\\VueComponentBase: %s","messagePattern":"Vue component class must be a descendant of Backend\\\\Classes\\\\VueComponentBase: (.+?)","errorType":"exception","errorClass":"SystemException","httpStatus":null,"severity":"error","filePath":"modules/backend/traits/VueMaker.php","lineNumber":216,"sourceCode":"            $path = substr($path, strlen($basePath));\n        }\n\n        $path = str_replace('\\\\', '/', $path);\n\n        return Request::getBasePath() . '/' . ltrim($path, '/');\n    }\n\n    /**\n     * makeVueComponent\n     */\n    protected function makeVueComponent($className)\n    {\n        if (!class_exists($className)) {\n            throw new SystemException(sprintf('Vue component class not found: %s', $className));\n        }\n\n        if (!is_subclass_of($className, VueComponentBase::class)) {\n            throw new SystemException(\n                sprintf('Vue component class must be a descendant of Backend\\Classes\\VueComponentBase: %s', $className)\n            );\n        }\n\n        return new $className($this);\n    }\n\n    /**\n     * isVueComponentRegistered\n     */\n    protected function isVueComponentRegistered($className)\n    {\n        return isset($this->vueComponentClasses[$className]);\n    }\n}\n","sourceCodeStart":198,"sourceCodeEnd":232,"githubUrl":"https://github.com/octobercms/october/blob/b608633a7e8922487d91a8161499020121c3b3bf/modules/backend/traits/VueMaker.php#L198-L232","documentation":"Even when the class exists, makeVueComponent() requires it to be a subclass of Backend\\Classes\\VueComponentBase (is_subclass_of), because registration drives Vue-component-specific APIs: dependency resolution, template paths, and ESM registration. A class extending a widget, controller, or nothing at all fails here with the class name included.","triggerScenarios":"registerVueComponent('Acme\\Demo\\SomeService') where SomeService extends another base (e.g. WidgetBase or FormWidgetBase) or no base at all; passing a helper class name where a Vue component was expected.","commonSituations":"Confusing backend Vue components with form widgets; copying a widget class as a template for a Vue component and forgetting to change the parent; restructuring class hierarchies during upgrades.","solutions":["Change the class to extend Backend\\Classes\\VueComponentBase.","If you meant a form widget, use makeFormWidget()/registerFormWidgets() instead of the Vue component pipeline.","Check that the class string is not pointing at a helper or a final intermediate class."],"exampleFix":"// before\nclass MediaManager extends \\Backend\\Classes\\WidgetBase\n{\n}\n\n// after\nuse Backend\\Classes\\VueComponentBase;\n\nclass MediaManager extends VueComponentBase\n{\n}","handlingStrategy":"validation","validationCode":"if (!is_subclass_of($class, \\Backend\\Classes\\VueComponentBase::class)) {\n    throw new InvalidArgumentException(\n        $class . ' must extend VueComponentBase to be registered as a Vue component'\n    );\n}\n$this->registerVueComponent($class);","typeGuard":"function isRegistrableVueComponent(string $class): bool\n{\n    return class_exists($class)\n        && is_subclass_of($class, \\Backend\\Classes\\VueComponentBase::class);\n}","tryCatchPattern":null,"preventionTips":["Start every backend Vue component from a VueComponentBase stub","Keep form widgets and Vue components in separate namespaces to avoid mixups"],"tags":["vue-component","inheritance","php","class-validation"],"backgroundTag":"wrong-base-class","analyzedSha":"b608633a7e8922487d91a8161499020121c3b3bf","analyzedAt":"2026-08-21T04:24:57.515Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}