symfony/translation · error · InvalidResourceException

The " " message is defined both with and without a context…

Error message

The "%s" message is defined both with and without a context, which is not supported because contexts are ignored in message keys.

What it means

PoFileLoader ignores message contexts in keys (msgctxt). If the same msgid appears once without a context and once with one (or with two different contexts), the loader cannot represent both entries and throws InvalidResourceException to avoid silently dropping translations.

Solutions

  1. Search the .po for the reported msgid and make context usage consistent: give every occurrence the same msgctxt or remove msgctxt from all.
  2. Deduplicate entries with `msguniq messages.po -o messages.po`.
  3. If contexts are genuinely needed, split messages into different domains/files.
  4. Re-export the catalogue from the translation tool ensuring each msgid appears once per context.

Example fix

// before (messages.po)
msgid "Save"
msgstr "Speichern"

msgctxt "menu"
msgid "Save"
msgstr "Speichern"
// after
msgctxt "menu"
msgid "Save"
msgstr "Speichern"  // single, consistently-contextualized entry
Defensive patterns

Strategy: validation

Validate before calling

$ids = [];
foreach (explode('\nmsg', file_get_contents($poFile)) as $block) {
    if (preg_match('/^id "((?:[^"\\]|\\.)*)"/m', $block, $m)) {
        $ctx = preg_match('/^ctxt /m', $block) ? 'with-context' : 'no-context';
        $key = $m[1];
        if (isset($ids[$key]) && $ids[$key] !== $ctx) {
            throw new \RuntimeException(sprintf('PO entry %s mixes context usage', $key));
        }
        $ids[$key] = $ctx;
    }
}

Try / catch

try {
    $catalogue = $loader->load($poFile, $locale);
} catch (InvalidResourceException $e) {
    error_log('PO context conflict: '.$e->getMessage());
    $catalogue = new MessageCatalogue($locale);
}

Prevention

When it happens

Trigger: addMessage() (via saveItem) when parsing a .po file containing duplicate msgid entries where one has msgctxt and the other does not, or two entries share a msgid but have different msgctxt values.

Common situations: Hand-merged .po files, translation tools exporting the same string with and without context, merge conflicts resolved incorrectly in catalogue files, copy-pasting entries into a .po.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at Loader/PoFileLoader.php:181

            $id = stripcslashes($item['ids']['singular']);
            if (isset($item['ids']['plural'])) {
                $id .= '|'.stripcslashes($item['ids']['plural']);
            }

            $translated = (array) $item['translated'];
            // PO are by definition indexed so sort by index.
            ksort($translated);
            // Make sure every index is filled.
            end($translated);
            $count = key($translated);
            // Fill missing spots with '-'.
            $empties = array_fill(0, $count + 1, '-');
            $translated += $empties;
            ksort($translated);

            $context = null !== $item['context'] ? stripcslashes($item['context']) : null;
            if (\array_key_exists($id, $this->contexts) && $context !== $this->contexts[$id]) {
                throw new InvalidResourceException(null === $context || null === $this->contexts[$id]
                    ? \sprintf('The "%s" message is defined both with and without a context, which is not supported because contexts are ignored in message keys.', $id)
                    : \sprintf('The "%s" message is defined twice with different contexts ("%s" and "%s"), which is not supported because contexts are ignored in message keys.', $id, $this->contexts[$id], $context));
            }
            $this->contexts[$id] = $context;

            $messages[$id] = stripcslashes(implode('|', $translated));

            if (null !== $context) {
                $this->metadata[$id] = ['context' => $context];
            }
        }
    }
}

View on GitHub (pinned to ae9e8a51bc)