symfony/translation · error · InvalidArgumentException

Invalid message format

Error message

Invalid message format (error #%d): 

What it means

Thrown by IntlFormatter::formatIntl when `new \MessageFormatter($locale, $message)` throws IntlException, i.e. the ICU message pattern itself is syntactically invalid for the given locale. The error code/message from intl_get_error_* are embedded in the exception text.

Solutions

  1. Read the appended intl error message to locate the syntax problem in the message string
  2. Fix the ICU pattern (balance braces, correct `{arg, type, format}` syntax)
  3. Validate messages with `msgfmt_format_message()` or an ICU message linter before deploying
  4. Isolate the offending message by formatting it directly with new \MessageFormatter($locale, $message)

Example fix

// before
'items.count': 'You have {count, plural, one {# item} other' // missing closing brace
// after
'items.count': 'You have {count, plural, one {# item} other {# items}}'
Defensive patterns

Strategy: try-catch

Validate before calling

$mf = msgfmt_create($locale, $message); if ($mf === false) { $err = intl_get_error_message(); // reject the message before runtime formatting }

Type guard

function isValidIcuPattern(string $locale, string $message): bool { return false !== msgfmt_format_message($locale, $message, []); }

Try / catch

try { $msg = $translator->trans($id, $params, $domain, $locale); } catch (InvalidArgumentException $e) { $this->logger->error('Bad ICU message '.$id.': '.$e->getMessage()); $msg = $id; }

Prevention

When it happens

Trigger: Formatting a translation message with malformed ICU syntax — unbalanced braces, invalid selector/argument syntax, bad plural rules — via $translator->trans() on an intl-formatted message.

Common situations: Hand-written translation files with ICU syntax mistakes (missing closing '}', stray quotes); translation files edited by non-developers or machine-generated; copy-pasting ICU patterns between formats.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at Formatter/IntlFormatter.php:40

{
    private bool $hasMessageFormatter;
    private array $cache = [];

    public function formatIntl(string $message, string $locale, array $parameters = []): string
    {
        // MessageFormatter constructor throws an exception if the message is empty
        if ('' === $message) {
            return '';
        }

        if (!$formatter = $this->cache[$locale][$message] ?? null) {
            if (!$this->hasMessageFormatter ??= class_exists(\MessageFormatter::class)) {
                throw new LogicException('Cannot parse message translation: please install the "intl" PHP extension or the "symfony/polyfill-intl-messageformatter" package.');
            }
            try {
                $this->cache[$locale][$message] = $formatter = new \MessageFormatter($locale, $message);
            } catch (\IntlException $e) {
                throw new InvalidArgumentException(\sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e);
            }
        }

        foreach ($parameters as $key => $value) {
            if (\in_array($key[0] ?? null, ['%', '{'], true)) {
                unset($parameters[$key]);
                $parameters[trim($key, '%{ }')] = $value;
            }
        }

        if (false === $message = $formatter->format($parameters)) {
            throw new InvalidArgumentException(\sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage());
        }

        return $message;
    }
}

View on GitHub (pinned to ae9e8a51bc)