getgrav/grav · error · RuntimeException

Failed to load file '%s': %s

Error message

Failed to load file '%s': %s

What it means

DataFile::load() wraps every read-or-decode failure into this message: the file path plus the underlying reason. The inner exception is either 'Bad Data' (raw read returned false — missing/unreadable file) or any RuntimeException from the configured formatter (invalid JSON/YAML/INI/CSV syntax). The original is chained, so $e->getPrevious() tells you whether the problem was I/O or parsing.

Source

Thrown at system/src/Grav/Framework/File/DataFile.php:54

        $this->formatter = $formatter;
    }

    /**
     * {@inheritdoc}
     * @see FileInterface::load()
     */
    public function load()
    {
        $raw = parent::load();

        try {
            if (!is_string($raw)) {
                throw new RuntimeException('Bad Data');
            }

            return $this->formatter->decode($raw);
        } catch (RuntimeException $e) {
            throw new RuntimeException(sprintf("Failed to load file '%s': %s", $this->getFilePath(), $e->getMessage()), $e->getCode(), $e);
        }
    }

    /**
     * {@inheritdoc}
     * @see FileInterface::save()
     */
    public function save($data): void
    {
        if (is_string($data)) {
            // Make sure that the string is valid data.
            try {
                $this->formatter->decode($data);
            } catch (RuntimeException $e) {
                throw new RuntimeException(sprintf("Failed to save file '%s': %s", $this->getFilePath(), $e->getMessage()), $e->getCode(), $e);
            }
            $encoded = $data;
        } else {

View on GitHub (pinned to 6040efed04)

Solutions

  1. Read the message: the quoted path identifies the file; the tail gives the reason ('Bad Data' = read failure, anything else = parse error with position).
  2. Validate the file in isolation: php -r 'json_decode(file_get_contents("f.json")); echo json_last_error_msg();' (or a YAML/INI linter) and fix the reported line.
  3. If the tail is 'Bad Data', fix existence/readability of the file (see the file-read family).
  4. Restore from backup or delete the file so Grav regenerates defaults; make sure the extension matches the content format.

Example fix

# before: RuntimeException "Failed to load file 'user/data/x.json': Syntax error"
php -r 'json_decode(file_get_contents("user/data/x.json")); echo json_last_error_msg(), PHP_EOL;'
# -> Syntax error  (fix the reported construct, e.g. trailing comma)
# after: $dataFile->load() succeeds
Defensive patterns

Strategy: try-catch

Validate before calling

$path = $dataFile->getFilePath();
if (is_file($path) && is_readable($path)) {
    $raw = file_get_contents($path);
    if (is_string($raw) && in_array($ext, ['json'], true) 
        && json_decode($raw) === null && json_last_error() !== JSON_ERROR_NONE) {
        // syntax problem: fix the file before calling load()
    }
}

Try / catch

try {
    $data = $dataFile->load();
} catch (\RuntimeException $e) {
    // path + reason are in the message; previous exception distinguishes I/O vs parse
    $log->error($e->getMessage());
    $data = $defaults; // or quarantine the file for manual repair
}

Prevention

When it happens

Trigger: Loading a data file with a syntax error for its format (bad JSON/YAML/INI/CSV); a missing or unreadable file (surfaces as '...: Bad Data'); a file whose extension maps to a different formatter than its actual content (JSON content in a .yaml file).

Common situations: Hand-edited plugin configuration with a typo (missing comma/quote); files truncated by a crash mid-save; BOM or smart quotes pasted from documentation; deploying files edited with wrong encoding; wrong extension-to-formatter mapping in configuration.

Related errors


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