symfony/translation · error · NotFoundResourceException
File " " not found.
Error message
File "%s" not found.
What it means
QtFileLoader checks file_exists() after confirming the resource is a local stream; a missing file raises NotFoundResourceException naming the path. This is a distinct, catchable signal that the translation catalogue file simply does not exist.
Solutions
- Check the exact path exists: `ls -l <resource>`; watch for case-sensitivity on Linux.
- Ensure your build/export step generates .ts files for every supported locale.
- Fix the resources path passed to the translator (Translator::addResource or loader config).
- Add a existence check with file_exists() before addResource to fail fast with a clearer app-level message.
Example fix
// before
$translator->addResource('qt', '/app/translations/messages.fr.ts', 'fr'); // file absent
// after
$file = '/app/translations/messages.fr.ts';
if (!is_file($file)) {
throw new \RuntimeException("Translation file missing: $file");
}
$translator->addResource('qt', $file, 'fr'); Defensive patterns
Strategy: validation
Validate before calling
if (!is_file($resource)) {
throw new \RuntimeException(sprintf('Translation file does not exist: %s (dir listing: %s)', $resource, implode(',', (array) @glob(dirname($resource).'/*'))));
} Type guard
function fileExistsCaseSensitive(string $path): bool {
return is_file($path) && basename($path) === basename(glob(dirname($path).'/'.basename($path), GLOB_NOCHECK)[0] ?? $path);
} Try / catch
try {
$catalogue = $loader->load($resource, $locale);
} catch (NotFoundResourceException $e) {
error_log('Missing translation file: '.$e->getMessage());
$catalogue = new MessageCatalogue($locale); // or fall back to default locale
} Prevention
- Generate .ts files for every supported locale in CI
- Use absolute, case-correct paths; test on a case-sensitive filesystem
- Add file_exists assertions before addResource in bootstrap
- Do not gitignore build-generated translation artifacts you deploy
When it happens
Trigger: load() with a local path that does not exist — wrong directory in the translator's resource loader config, locale/domain file naming mismatch (e.g. messages.fr.ts absent), file deleted or never deployed.
Common situations: Per-locale files not generated for new languages, .gitignore excluding translation artifacts, path typos or case-sensitivity differences on Linux, container volumes missing the translations directory.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- The " " file does not exist.
- Error opening file " ".
- File " " not found.
- File " " not found.
- Cannot load resource
AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15).
Data as JSON: /api/errors/0911e549588344b5.
Report an issue: GitHub.
Appendix: source
Thrown at Loader/QtFileLoader.php:39
/**
* QtFileLoader loads translations from QT Translations XML files.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class QtFileLoader implements LoaderInterface
{
public function load(mixed $resource, string $locale, string $domain = 'messages'): MessageCatalogue
{
if (!class_exists(XmlUtils::class)) {
throw new RuntimeException('Loading translations from the QT format requires the Symfony Config component.');
}
if (!stream_is_local($resource)) {
throw new InvalidResourceException(\sprintf('This is not a local file "%s".', $resource));
}
if (!file_exists($resource)) {
throw new NotFoundResourceException(\sprintf('File "%s" not found.', $resource));
}
try {
$dom = XmlUtils::loadFile($resource);
} catch (\InvalidArgumentException $e) {
throw new InvalidResourceException(\sprintf('Unable to load "%s".', $resource), $e->getCode(), $e);
}
$internalErrors = libxml_use_internal_errors(true);
libxml_clear_errors();
$xpath = new \DOMXPath($dom);
$nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
$catalogue = new MessageCatalogue($locale);
if (1 == $nodes->length) {
$translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
foreach ($translations as $translation) {View on GitHub (pinned to ae9e8a51bc)