getgrav/grav · error · InvalidArgumentException
Bad Data Formatter
Error message
Bad Data Formatter
What it means
AbstractFilesystemStorage::initDataFormatter() validates the configured storage formatter before instantiating it. The 'class' entry of the formatter config (or the bare class-name string) must be a class that implements FileFormatterInterface, otherwise an InvalidArgumentException('Bad Data Formatter') is thrown. This is a hard configuration error raised the moment a Flex directory with filesystem storage is created.
Source
Thrown at system/src/Grav/Framework/Flex/Storage/AbstractFilesystemStorage.php:131
'key' => $key
];
}
/**
* @param string|array $formatter
* @return void
*/
protected function initDataFormatter($formatter): void
{
// Initialize formatter.
if (!is_array($formatter)) {
$formatter = ['class' => $formatter];
}
$formatterClassName = $formatter['class'] ?? JsonFormatter::class;
$formatterOptions = $formatter['options'] ?? [];
if (!is_a($formatterClassName, FileFormatterInterface::class, true)) {
throw new \InvalidArgumentException('Bad Data Formatter');
}
$this->dataFormatter = new $formatterClassName($formatterOptions);
}
/**
* @param string $filename
* @return string|null
*/
protected function detectDataFormatter(string $filename): ?string
{
if (preg_match('|(\.[a-z0-9]*)$|ui', $filename, $matches)) {
switch ($matches[1]) {
case '.json':
return JsonFormatter::class;
case '.yaml':
return YamlFormatter::class;
case '.md':View on GitHub (pinned to 6040efed04)
Solutions
- Open the Flex blueprint/storage config and verify storage.formatter.class is a fully-qualified class name implementing Grav\Framework\File\Formatter\FileFormatterInterface (check with is_a($class, FileFormatterInterface::class, true)).
- Fix typos and use the built-in FQCNs: JsonFormatter, YamlFormatter, MarkdownFormatter, SerializeFormatter, IniFormatter in Grav\Framework\File\Formatter.
- If using a custom formatter, make sure the file is autoloaded (composer PSR-4 mapping, plugin class loaded) and the class implements FileFormatterInterface.
- After fixing, clear cache so the directory is re-instantiated (bin/grav clearcache).
Example fix
# before (blueprint storage config)
storage:
class: Grav\Framework\Flex\Storage\FolderStorage
options:
formatter:
class: 'Grav\Framework\File\Formatter\JsonFormater' # typo -> Bad Data Formatter
# after
storage:
class: Grav\Framework\Flex\Storage\FolderStorage
options:
formatter:
class: 'Grav\Framework\File\Formatter\JsonFormatter' Defensive patterns
Strategy: validation
Validate before calling
use Grav\Framework\File\Formatter\FileFormatterInterface;
$class = $storageConfig['options']['formatter']['class']
?? $storageConfig['options']['formatter']
?? \Grav\Framework\File\Formatter\JsonFormatter::class;
if (!\is_string($class) || !\is_a($class, FileFormatterInterface::class, true)) {
throw new \InvalidArgumentException("Invalid formatter class: {$class}");
} Type guard
function isValidFormatterClass(string $class): bool
{
return \class_exists($class)
&& \is_a($class, \Grav\Framework\File\Formatter\FileFormatterInterface::class, true);
} Try / catch
try {
$directory = $flex->getDirectory($type);
} catch (\InvalidArgumentException $e) {
if ('Bad Data Formatter' === $e->getMessage()) {
// fall back to default JSON storage for this directory
$blueprint['storage']['options']['formatter'] = \Grav\Framework\File\Formatter\JsonFormatter::class;
$directory = $flex->getDirectory($type);
} else {
throw $e;
}
} Prevention
- Always use fully-qualified built-in formatter class names from Grav\Framework\File\Formatter.
- In CI or a preflight script, assert every Flex storage formatter passes is_a($class, FileFormatterInterface::class, true).
- When copying Flex blueprints between projects, verify the custom formatter package is in composer.json.
When it happens
Trigger: Defining a Flex directory (blueprint or plugin config) whose storage options set 'formatter' to a class name that is not a FileFormatterInterface implementation; misspelling a built-in formatter class (e.g. 'Grav\Framework\File\Formatter\JsonFormater'); pointing 'class' at a class that only exists in a newer/older Grav version than the one installed; passing a namespaced string of a class that failed to autoload.
Common situations: Custom Flex directory with storage.formatter.class set to a project-local formatter that was deleted or moved; typo in the FQCN; upgrading Grav changed formatter namespaces (they live in Grav\Framework\File\Formatter); copying a blueprint from another project whose custom formatter package is not installed.
Related errors
- Unknown extension type
- Bad storage class: %s
- Invalid storage key: "%s"
- No backups defined...
- Backup location: {$backup_root} does not exist...
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/3daaf7a54004a2e0.
Report an issue: GitHub.