symfony/translation · error · InvalidResourceException
$rb->getErrorMessage()
Error message
$rb->getErrorMessage()
What it means
When the ResourceBundle loads but ICU reports a failure code (intl_is_failure), the loader wraps ICU's own error message and code in InvalidResourceException. This means the bundle exists but ICU rejected it — e.g. a format/version mismatch between the .res file and the ICU library.
Solutions
- Read the exception's ICU error code and look it up in ICU's UErrorCode documentation to identify the exact failure.
- Regenerate .res bundles with genrb from a matching (or older) ICU toolchain.
- Upgrade the PHP intl extension / ICU library to a version compatible with the bundle files.
- Re-download or re-deploy the resource files if they are truncated or corrupted.
Example fix
// before
cat = $loader->load('messages.res', 'fr'); // ICU failure code
// after
$rb = new \ResourceBundle('fr', 'messages.res');
if (intl_is_failure($rb->getErrorCode())) {
throw new \RuntimeException('ICU error '.$rb->getErrorCode().': rebuild bundles with matching ICU');
} Defensive patterns
Strategy: try-catch
Validate before calling
$rb = new \ResourceBundle($locale, $resource);
if (!$rb || intl_is_failure($rb->getErrorCode())) {
throw new \RuntimeException('ICU error '.$rb->getErrorCode().': '.$rb->getErrorMessage());
} Type guard
function icuBundleLoads(string $locale, string $resource): bool {
$rb = @new \ResourceBundle($locale, $resource);
return $rb !== null && !intl_is_failure($rb->getErrorCode());
} Try / catch
try {
$catalogue = $loader->load($resource, $locale);
} catch (InvalidResourceException $e) {
error_log('ICU failure: '.$e->getMessage().' code '.$e->getCode());
$catalogue = $fallbackLoader->load($fallbackResource, $locale);
} Prevention
- Regenerate bundles with a genrb version matching the runtime ICU
- Record the ICU version used to build bundles in your build metadata
- Add a smoke test that loads every locale bundle in CI
- Handle IntlException/ICU codes explicitly rather than ignoring them
When it happens
Trigger: load() on a .res file whose internal ICU error code (UErrorCode) indicates failure — truncated or wrongly-versioned bundle data, mismatched ICU version that produced the file. Raised in testDatEnglishLoad/testDatFrenchLoad flows.
Common situations: .res files generated with a newer ICU than the runtime intl extension; partially uploaded/truncated resource files; bundles referencing fallback locales missing from the 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
- Cannot load resource
- $rb->getErrorMessage()
- Cannot parse message translation: please install the "intl"…
- This is not a local file
- File " " not found.
AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15).
Data as JSON: /api/errors/5fcaa5efa27cf3f9.
Report an issue: GitHub.
Appendix: source
Thrown at Loader/IcuResFileLoader.php:45
{
if (!stream_is_local($resource)) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!is_dir($resource)) {
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(DirectoryResource::class)) {
$catalogue->addResource(new DirectoryResource($resource));
}
return $catalogue;
}
/**
* Flattens an ResourceBundle.
*
* The scheme used is:
* key { key2 { key3 { "value" } } }View on GitHub (pinned to ae9e8a51bc)