{"record":{"id":"a312bce2250a55a4","repo":"getgrav/grav","slug":"bad-index-class-s","errorCode":null,"errorMessage":"Bad index class: %s","messagePattern":"Bad index class: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Framework/Flex/FlexDirectory.php","lineNumber":612,"sourceCode":"        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        }\n\n        return $className::createFromArray($entries, $this, $keyField);\n    }\n\n    /**\n     * @return string\n     */\n    public function getObjectClass(): string\n    {\n        if (!$this->objectClassName) {\n            $this->objectClassName = $this->getConfig('data.object', GenericObject::class);\n        }\n\n        return $this->objectClassName;\n    }\n\n    /**","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Flex/FlexDirectory.php#L594-L630","documentation":"FlexDirectory::createIndex() (line 612) creates index objects from the blueprint key data.index (default GenericIndex), checking is_a(..., FlexIndexInterface::class, true) before instantiating. A class name that is misspelled, missing, or not a FlexIndex implementation throws 'Bad index class'; indexes are created on every directory lookup, so the directory is effectively unusable until fixed.","triggerScenarios":"A custom flex type with a custom data.index class that fails to autoload or does not extend FlexIndex; renaming the index class in an update without updating shipped blueprints; cached blueprint/config in user:// still referencing an old class after a plugin upgrade.","commonSituations":"Plugin upgrades that move index classes; user config overriding flex type settings with stale names; environments where composer autoload differs (missing regenerated autoload).","solutions":["Point data.index at an autoloaded class implementing Grav\\Framework\\Flex\\Interfaces\\FlexIndexInterface (normally extending Grav\\Framework\\Flex\\FlexIndex).","Run composer dump-autoload and clear Grav cache so blueprint/config overrides are re-read.","Remove stale data.index overrides in user:// config/blueprints after upgrading the plugin that owns the type."],"exampleFix":"# before (user config override)\ndata:\n  index: 'Vendor\\Plugin\\Flex\\OldIndex'  # renamed in v2\n\n# after\ndata:\n  index: 'Vendor\\Plugin\\Flex\\ThingsIndex'","handlingStrategy":"validation","validationCode":"$class = $directory->getConfig('data.index', \\Grav\\Framework\\Flex\\GenericIndex::class);\nif (!class_exists($class) || !is_a($class, \\Grav\\Framework\\Flex\\Interfaces\\FlexIndexInterface::class, true)) {\n    // fix blueprint before calling getIndex()/createIndex()\n}","typeGuard":"function isValidFlexIndexClass(string $class): bool\n{\n    return class_exists($class)\n        && \\is_a($class, \\Grav\\Framework\\Flex\\Interfaces\\FlexIndexInterface::class, true);\n}","tryCatchPattern":"try {\n    $index = $directory->createIndex($entries);\n} catch (\\RuntimeException $e) {\n    if (str_starts_with($e->getMessage(), 'Bad index class')) {\n        // configuration defect: log the class name and stop\n    }\n}","preventionTips":["Assert custom index classes extend FlexIndex during plugin boot.","Remove stale data.index overrides in user:// config after plugin upgrades.","Regenerate the autoloader when class names change."],"tags":["flex","configuration","class-loading","blueprint","index"],"backgroundTag":"invalid-index-class-config","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}