{"record":{"id":"4c37dbcff47a13f1","repo":"getgrav/grav","slug":"bad-collection-class-s","errorCode":null,"errorMessage":"Bad collection class: %s","messagePattern":"Bad collection class: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Flex/FlexDirectory.php","lineNumber":595,"sourceCode":"        if (!is_a($className, FlexObjectInterface::class, true)) {\n            throw new \\RuntimeException('Bad object class: ' . $className);\n        }\n\n        return new $className($data, $key, $this, $validate);\n    }\n\n    /**\n     * @param array $entries\n     * @param string|null $keyField\n     * @return FlexCollectionInterface\n     * @phpstan-return FlexCollectionInterface<FlexObjectInterface>\n     */\n    public function createCollection(array $entries, ?string $keyField = null): FlexCollectionInterface\n    {\n        /** phpstan-var class-string $className */\n        $className = $this->collectionClassName ?: $this->getCollectionClass();\n        if (!is_a($className, FlexCollectionInterface::class, true)) {\n            throw new \\RuntimeException('Bad collection class: ' . $className);\n        }\n\n        return $className::createFromArray($entries, $this, $keyField);\n    }\n\n    /**\n     * @param array $entries\n     * @param string|null $keyField\n     * @return FlexIndexInterface\n     * @phpstan-return FlexIndexInterface<FlexObjectInterface>\n     */\n    public function createIndex(array $entries, ?string $keyField = null): FlexIndexInterface\n    {\n        /** @phpstan-var class-string $className */\n        $className = $this->indexClassName ?: $this->getIndexClass();\n        if (!is_a($className, FlexIndexInterface::class, true)) {\n            throw new \\RuntimeException('Bad index class: ' . $className);\n        }","sourceCodeStart":577,"sourceCodeEnd":613,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Flex/FlexDirectory.php#L577-L613","documentation":"FlexDirectory::createCollection() (line 595) builds collections using the class from the blueprint key data.collection (default GenericCollection), verifying with is_a(..., FlexCollectionInterface::class, true) first. If the configured name is misspelled, not autoloaded, or does not implement the interface, it throws 'Bad collection class'. Like the object check, a non-existent class string fails is_a() and produces the same message.","triggerScenarios":"A custom flex type whose data.collection entry names a class that is not a FlexCollection implementation; renaming a collection class without updating the blueprint; YAML escaping errors doubling backslashes; the providing plugin being disabled so its autoloader no longer resolves the class.","commonSituations":"Custom flex types with specialized collection classes; plugin refactors; blueprint overrides in user:// config that stale-copy an old class name.","solutions":["Point data.collection at an autoloaded class implementing Grav\\Framework\\Flex\\Interfaces\\FlexCollectionInterface (normally extending Grav\\Framework\\Flex\\FlexCollection).","Confirm runtime autoloadability (composer dump-autoload; plugin enabled).","Use single-quoted YAML class names and re-check backslash escaping."],"exampleFix":"# before (blueprint.yaml)\ndata:\n  collection: 'Vendor\\Plugin\\Flex\\ThingsCollection'  # class does not exist / wrong interface\n\n# after\ndata:\n  collection: 'Grav\\Framework\\Flex\\GenericCollection'","handlingStrategy":"validation","validationCode":"$class = $directory->getConfig('data.collection', \\Grav\\Framework\\Flex\\GenericCollection::class);\nif (!class_exists($class) || !is_a($class, \\Grav\\Framework\\Flex\\Interfaces\\FlexCollectionInterface::class, true)) {\n    // fix blueprint before calling getCollection()/createCollection()\n}","typeGuard":"function isValidFlexCollectionClass(string $class): bool\n{\n    return class_exists($class)\n        && \\is_a($class, \\Grav\\Framework\\Flex\\Interfaces\\FlexCollectionInterface::class, true);\n}","tryCatchPattern":"try {\n    $collection = $directory->createCollection($entries);\n} catch (\\RuntimeException $e) {\n    if (str_starts_with($e->getMessage(), 'Bad collection class')) {\n        // configuration defect: log the class name and stop\n    }\n}","preventionTips":["Assert custom collection classes extend FlexCollection during plugin boot.","Keep blueprint class names in sync with plugin refactors.","Clear config cache after changing flex blueprint settings."],"tags":["flex","configuration","class-loading","blueprint","collections"],"backgroundTag":"invalid-collection-class-config","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}