PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

The Intl extension does not support Accounting Formats…

Error message

The Intl extension does not support Accounting Formats without ICU 53

What it means

Thrown by the Accounting number-format Wizard when a locale-aware accounting mask is requested but the installed ICU library is older than version 53. Accounting formats rely on NumberFormatter::CURRENCY_ACCOUNTING, which ICU only supports from 53 onwards, so getLocaleFormat() refuses to run rather than emit a wrong mask. It fires only when the intl extension reports an ICU version below 53.0, which is rare on current PHP builds.

Solutions

  1. Upgrade PHP/intl so it links ICU >= 53 (verify with `echo INTL_ICU_VERSION;`), usually via current distro or sury/ondrej-php packages
  2. Build the accounting format without a locale so the wizard uses its built-in mask (pass '' as the locale argument)
  3. Catch the exception and fall back to a hand-written format code such as '_-"€"* #,##0.00_-;-"€"* #,##0.00_-;_-"€"* "-"??_-;_-@_-'

Example fix

// before
$mask = (new Accounting(2, '€', 'de-DE'))->format();

// after (guard for old ICU)
if (defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '53.0', '>=')) {
    $mask = (new Accounting(2, '€', 'de-DE'))->format();
} else {
    $mask = '_-"€"* #,##0.00_-;-"€"* #,##0.00_-;_-"€"* "-"??_-;_-@_-';
}
Defensive patterns

Strategy: validation

Validate before calling

$icuOk = extension_loaded('intl') && defined('INTL_ICU_VERSION') && version_compare(INTL_ICU_VERSION, '53.0', '>=');
if ($icuOk) {
    $mask = (new Accounting(2, '€', 'de-DE'))->format();
} else {
    $mask = '_-"€"* #,##0.00_-;-"€"* #,##0.00_-;_-"€"* "-"??_-;_-@_-';
}

Type guard

function icuSupportsAccountingFormats(): bool
{
    return extension_loaded('intl')
        && defined('INTL_ICU_VERSION')
        && version_compare(INTL_ICU_VERSION, '53.0', '>=');
}

Try / catch

try {
    $mask = $accountingWizard->format();
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
    // ICU too old: fall back to a hardcoded accounting format code
    $mask = '_-"€"* #,##0.00_-;-"€"* #,##0.00_-;_-"€"* "-"??_-;_-@_-';
}

Prevention

When it happens

Trigger: Calling (new Accounting(2, '€', 'de-DE'))->format(), or any Accounting wizard with a non-empty locale, on a PHP build whose intl extension links ICU < 53 (checked via INTL_ICU_VERSION).

Common situations: Legacy hosting, old Ubuntu/Debian PHP packages, outdated XAMPP/WAMP bundles, or containers built from very old base images where PHP was upgraded but the ICU library was not.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/6465c5fb5b28fe7a. Report an issue: GitHub.

Appendix: source

Thrown at src/PhpSpreadsheet/Style/NumberFormat/Wizard/Accounting.php:21

namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;

use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Exception;

class Accounting extends CurrencyBase
{
    protected ?bool $overrideSpacing = true;

    protected ?CurrencyNegative $overrideNegative = CurrencyNegative::parentheses;

    /**
     * @throws Exception if the Intl extension and ICU version don't support Accounting formats
     */
    protected function getLocaleFormat(): string
    {
        if (self::icuVersion() < 53.0) {
            // @codeCoverageIgnoreStart
            throw new Exception('The Intl extension does not support Accounting Formats without ICU 53');
            // @codeCoverageIgnoreEnd
        }

        // Scrutinizer does not recognize CURRENCY_ACCOUNTING
        $formatter = new Locale($this->fullLocale, NumberFormatter::CURRENCY_ACCOUNTING);
        $mask = $formatter->format($this->stripLeadingRLM);
        if ($this->decimals === 0) {
            $mask = (string) preg_replace('/\.0+/miu', '', $mask);
        }

        return str_replace('¤', $this->formatCurrencyCode(), $mask);
    }

    public static function icuVersion(): float
    {
        [$major, $minor] = explode('.', INTL_ICU_VERSION);

        return (float) "{$major}.{$minor}";

View on GitHub (pinned to 65b080eef4)