symfony/translation · error · InvalidResourceException
This is not a local file
Error message
This is not a local file "%s".
What it means
QtFileLoader only reads local filesystem resources; stream_is_local() rejects remote URLs/wrappers such as http:// or ftp://, since XmlUtils::loadFile requires a local path. It throws InvalidResourceException with the offending resource path.
Solutions
- Download the .ts file to a local temp path (file_get_contents/curl) and pass the local path to load().
- Mount or sync remote translation files locally as part of deployment.
- If resources truly must be remote, write a custom loader that streams content and parses via a DOMDocument loaded from a string.
- Fix config that interpolates a base URL into the resource path.
Example fix
// before
$loader->load('https://cdn.example.com/messages.fr.ts', 'fr');
// after
$tmp = sys_get_temp_dir().'/messages.fr.ts';
file_put_contents($tmp, file_get_contents('https://cdn.example.com/messages.fr.ts'));
$loader->load($tmp, 'fr'); Defensive patterns
Strategy: validation
Validate before calling
if (!stream_is_local($resource)) {
throw new \RuntimeException(sprintf('Translation resource must be local, got: %s', $resource));
} Type guard
function isLocalFilePath(mixed $resource): bool {
return is_string($resource) && stream_is_local($resource) && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $resource);
} Try / catch
try {
$catalogue = $loader->load($resource, $locale);
} catch (InvalidResourceException $e) {
if (str_contains($e->getMessage(), 'not a local file')) {
$local = downloadToTemp($resource);
$catalogue = $loader->load($local, $locale);
} else {
throw $e;
}
} Prevention
- Keep translation files on local disk; sync remote sources at deploy time
- Do not interpolate URLs into resource paths from env config
- Validate resource paths against a whitelist of local directories
- Document that loaders require local streams
When it happens
Trigger: load() called with a non-local stream target, e.g. 'https://example.com/messages.ts', 'ftp://...', or a custom stream wrapper — raised in testLoad paths.
Common situations: Configuring the translation resource path from a CDN/remote origin, passing a URL built from environment config, trying to load bundles straight from object storage.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Loading translations from the QT format requires the…
- File " " not found.
- Unable to load " ".
- The Translator does not support the following options
- The file dumper needs a path option.
AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15).
Data as JSON: /api/errors/1998411bacd4767a.
Report an issue: GitHub.
Appendix: source
Thrown at Loader/QtFileLoader.php:35
use Symfony\Component\Translation\Exception\NotFoundResourceException;
use Symfony\Component\Translation\Exception\RuntimeException;
use Symfony\Component\Translation\MessageCatalogue;
/**
* 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.'"]');
View on GitHub (pinned to ae9e8a51bc)