symfony/translation · error · InvalidResourceException

This is neither a file nor an XLIFF string

Error message

This is neither a file nor an XLIFF string "%s".

What it means

The resource is a local, existing path but is neither a regular file nor an XML string — typically a directory — so the loader throws InvalidResourceException. is_file() distinguishes regular files from directories and special files.

Solutions

  1. Pass a single .xlf/.xliff file path, not a directory.
  2. Iterate the directory yourself (glob('translations/*.xlf')) and call load() per file.
  3. Validate with is_file($resource) before calling load().

Example fix

// before
$loader->load('translations/', 'en'); // directory
// after
foreach (glob('translations/*.xlf') as $file) {
    $loader->load($file, 'en');
}
Defensive patterns

Strategy: validation

Validate before calling

if (!is_file($resource) && !str_starts_with(ltrim((string) $resource), '<?xml')) {
    throw new \InvalidArgumentException(sprintf('Expected an XLIFF file, got: %s', $resource));
}

Try / catch

try {
    $catalogue = $loader->load($resource, $locale);
} catch (InvalidResourceException $e) {
    if (str_contains($e->getMessage(), 'neither a file nor an XLIFF string')) {
        // you probably passed a directory; enumerate files instead
    }
}

Prevention

When it happens

Trigger: Passing a directory path (e.g. the translations folder itself) as $resource to XliffFileLoader::load().

Common situations: Configuration mistake where a directory configured for translation lookup is fed to the loader directly instead of individual files.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at Loader/XliffFileLoader.php:48

class XliffFileLoader 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 Xliff format requires the Symfony Config component.');
        }

        if (!$this->isXmlString($resource)) {
            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));
            }

            if (!is_file($resource)) {
                throw new InvalidResourceException(\sprintf('This is neither a file nor an XLIFF string "%s".', $resource));
            }
        }

        try {
            if ($this->isXmlString($resource)) {
                $dom = XmlUtils::parse($resource);
            } else {
                $dom = XmlUtils::loadFile($resource);
            }
        } catch (\InvalidArgumentException|XmlParsingException|InvalidXmlException $e) {
            throw new InvalidResourceException(\sprintf('Unable to load "%s": ', $resource).$e->getMessage(), $e->getCode(), $e);
        }

        if ($errors = XliffUtils::validateSchema($dom)) {
            throw new InvalidResourceException(\sprintf('Invalid resource provided: "%s"; Errors: ', $resource).XliffUtils::getErrorsAsString($errors));
        }

        $catalogue = new MessageCatalogue($locale);

View on GitHub (pinned to ae9e8a51bc)