symfony/translation · error · InvalidResourceException

Cannot load resource

Error message

Cannot load resource "%s".

What it means

IcuDatFileLoader::load() constructs a \ResourceBundle($locale, $resource); if the bundle cannot be created (null/false returned, caught exception) it throws InvalidResourceException('Cannot load resource...'). The file exists but ResourceBundle could not parse or open it as a valid ICU bundle.

Solutions

  1. Regenerate the .dat bundle with an ICU version matching your PHP intl extension's ICU.
  2. Verify the bundle path is the base path ResourceBundle expects (bundles directory pattern).
  3. Test the bundle directly: new \ResourceBundle($locale, $path) and inspect getErrorCode().
  4. Confirm the intl extension is installed and its ICU version (php --ri intl) is compatible with the bundle.

Example fix

// before
$rb = new \ResourceBundle('en_FR', '/app/resources/messages'); // bundle has no en_FR
// after
$rb = new \ResourceBundle('fr_FR', '/app/resources/messages');
if (!$rb || intl_is_failure($rb->getErrorCode())) {
    throw new \RuntimeException('Invalid ICU bundle: '.$rb?->getErrorMessage());
}
Defensive patterns

Strategy: try-catch

Validate before calling

$rb = new \ResourceBundle($locale, $basePath);
if (!$rb || intl_is_failure($rb->getErrorCode())) {
    throw new \RuntimeException('Unusable ICU bundle: '.($rb?->getErrorMessage() ?? 'null bundle'));
}

Type guard

function isValidResourceBundle(\ResourceBundle $rb): bool { return intl_is_failure($rb->getErrorCode()) === false; }

Try / catch

try {
    $catalogue = $loader->load($basePath, $locale);
} catch (Symfony\Component\Translation\Exception\InvalidResourceException $e) {
    error_log('ICU bundle invalid: '.$e->getMessage());
    $catalogue = new MessageCatalogue($locale);
}

Prevention

When it happens

Trigger: ResourceBundle constructor returns falsy for an existing but invalid/empty/incompatible .dat bundle, or the bundle lacks the requested locale data and ResourceBundle reports it as missing.

Common situations: Corrupted or truncated .dat file, bundle compiled with an ICU version incompatible with the PHP intl extension, wrong bundle path passed so ResourceBundle finds nothing, or missing intl/icu data.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15). Data as JSON: /api/errors/816b5a9c2f93f85d. Report an issue: GitHub.

Appendix: source

Thrown at Loader/IcuDatFileLoader.php:43

{
    public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
    {
        if (!stream_is_local($resource.'.dat')) {
            throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
        }

        if (!file_exists($resource.'.dat')) {
            throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
        }

        try {
            $rb = new \ResourceBundle($locale, $resource);
        } catch (\Exception) {
            $rb = null;
        }

        if (!$rb) {
            throw new InvalidResourceException(\sprintf('Cannot load resource "%s".', $resource));
        } elseif (intl_is_failure($rb->getErrorCode())) {
            throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
        }

        $messages = $this->flatten($rb);
        $catalogue = new MessageCatalogue($locale);
        $catalogue->add($messages, $domain);

        if (class_exists(FileResource::class)) {
            $catalogue->addResource(new FileResource($resource.'.dat'));
        }

        return $catalogue;
    }
}

View on GitHub (pinned to ae9e8a51bc)