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

  1. 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)).
  2. Fix typos and use the built-in FQCNs: JsonFormatter, YamlFormatter, MarkdownFormatter, SerializeFormatter, IniFormatter in Grav\Framework\File\Formatter.
  3. If using a custom formatter, make sure the file is autoloaded (composer PSR-4 mapping, plugin class loaded) and the class implements FileFormatterInterface.
  4. 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

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


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/3daaf7a54004a2e0. Report an issue: GitHub.