getgrav/grav · error · RuntimeException

Cannot save data, string required

Error message

Cannot save data, string required

What it means

Grav\Framework\File\File is the raw, format-agnostic file handler: its save() demands a PHP string and throws for any other type before delegating to AbstractFile::save(). Structured data (arrays/objects) belongs to DataFile or a formatter-aware class, which encodes automatically. This is a strict API-contract error — nothing was written.

Source

Thrown at system/src/Grav/Framework/File/File.php:30

namespace Grav\Framework\File;

use RuntimeException;
use function is_string;

/**
 * Class File
 * @package Grav\Framework\File
 */
class File extends AbstractFile
{
    /**
     * {@inheritdoc}
     * @see FileInterface::save()
     */
    public function save($data): void
    {
        if (!is_string($data)) {
            throw new RuntimeException('Cannot save data, string required');
        }

        parent::save($data);
    }
}

View on GitHub (pinned to 6040efed04)

Solutions

  1. Cast the payload: $file->save((string) $data).
  2. Switch to Grav\Framework\File\DataFile (or the filesystem/formatter factory) when saving structured data.
  3. Add a type check at the call site (is_string($data)) or a native string type hint in your own wrapper.

Example fix

// before
$file = new \Grav\Framework\File\File($path);
$file->save(['foo' => 'bar']); // RuntimeException: Cannot save data, string required

// after (structured data -> DataFile via formatter-aware factory)
$file = $filesystem->file($path); // DataFile bound to the right formatter
$file->save(['foo' => 'bar']);

// or raw string
$file->save((string) json_encode(['foo' => 'bar']));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_string($data)) {
    $data = (string) $data; // or switch to a DataFile for structured data
}
$file->save($data);

Type guard

function isRawStringPayload(mixed $data): bool
{
    return is_string($data);
}

Try / catch

try {
    $file->save($data);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'string required')) {
        $file->save((string) $data);
    }
}

Prevention

When it happens

Trigger: Calling save(['key' => 'value']), save(123) or save($object) on a File instance: using File where DataFile was intended; passing an un-cast scalar from config; refactors that changed the payload from string to array without changing the class.

Common situations: Copy-pasting DataFile examples against a File object; switching persistence from serialized strings to structured arrays; saving computed ints/floats/bools without an explicit cast.

Related errors


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