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
- Read the message: the quoted path identifies the file; the tail gives the reason ('Bad Data' = read failure, anything else = parse error with position).
- 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.
- If the tail is 'Bad Data', fix existence/readability of the file (see the file-read family).
- 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
- Lint all data/config files in CI so syntax errors never deploy.
- Write files via the formatter's save() rather than manual edits.
- Reject BOM and smart quotes at input boundaries.
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
- Cannot unserialize Block: %s
- Bad Data
- Failed to save file '%s': %s
- CSV header missing
- Badly formatted CSV line: {line}
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/6c511491f7e877bd.
Report an issue: GitHub.