symfony/translation · error · InvalidResourceException

$rb->getErrorMessage()

Error message

$rb->getErrorMessage()

What it means

IcuDatFileLoader::load() throws InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode()) when intl_is_failure() reports the ResourceBundle's error code is a failure. The message is the ICU/intl error text itself, so the thrown message equals whatever ICU reported (e.g. 'U_MISSING_RESOURCE_ERROR').

Solutions

  1. Log/inspect the ICU error code (the exception code) and map it: U_MISSING_RESOURCE_ERROR means the locale is absent from the bundle.
  2. Rebuild the bundle to include the requested locales.
  3. Fix filesystem access (permissions/open_basedir) if the code is U_FILE_ACCESS_ERROR.
  4. Align the PHP intl ICU version with the version used to compile the bundles.

Example fix

// before
$rb = new \ResourceBundle('es', '/app/resources/messages'); // bundle only contains en, fr
// after
$locales = ['en', 'fr'];
if (!in_array('es', $locales, true)) {
    throw new \RuntimeException('Locale es missing from ICU bundle; rebuild with msgfmt.');
}
Defensive patterns

Strategy: try-catch

Validate before calling

$rb = new \ResourceBundle($locale, $basePath);
if ($rb && intl_is_failure($rb->getErrorCode())) {
    throw new \RuntimeException('ICU failure '.$rb->getErrorCode().': '.$rb->getErrorMessage());
}

Type guard

function intlBundleHealthy(\ResourceBundle $rb): bool { return !intl_is_failure($rb->getErrorCode()); }

Try / catch

try {
    $catalogue = $loader->load($basePath, $locale);
} catch (Symfony\Component\Translation\Exception\InvalidResourceException $e) {
    // $e->getCode() is the ICU error code (e.g. U_MISSING_RESOURCE_ERROR)
    error_log('ICU error '.$e->getCode().': '.$e->getMessage());
}

Prevention

When it happens

Trigger: ResourceBundle was created successfully but its internal error code is an ICU failure (e.g. U_MISSING_RESOURCE_ERROR, U_FILE_ACCESS_ERROR), detected via intl_is_failure($rb->getErrorCode()).

Common situations: Bundle file exists but the requested locale table is missing inside it, ICU data file access issues (permissions, open_basedir), or an ICU version mismatch producing warnings escalated to failures.

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/8b85137981b59375. Report an issue: GitHub.

Appendix: source

Thrown at Loader/IcuDatFileLoader.php:45

    {
        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)