# Fix the formatjs date format range error on invalid locale data

## TL;DR

The locale tag you passed is not valid BCP47, so Intl rejects it before formatjs even starts. Validate the tag and fall back to a known-good one. This usually happens when a locale string comes from user input or a CMS with underscores instead of hyphens.

## The error

```text
RangeError: Incorrect locale information provided
at DateTimeFormat (formatDate with locale "en_US")
```

## Fix it

### Step 1: Confirm the tag is the problem

```bash
node -e "try{new Intl.DateTimeFormat('en_US')}catch(e){console.log('bad:',e.message)}; console.log('good:',new Intl.DateTimeFormat('en-US').resolvedOptions().locale)"
```

Expected: en_US throws, en-US resolves. Underscore is the giveaway.

### Step 2: Normalize the locale where it enters your code

```bash
node -e "const fix=s=>s.replace(/_/g,'-'); console.log(fix('en_US'), fix('pt_BR'))"
```

Expected: Every locale string becomes hyphenated BCP47 before it reaches formatjs.

### Step 3: Add a fallback for tags that still fail

```bash
node -e "function safe(l){try{new Intl.DateTimeFormat(l);return l}catch(e){return 'en-US'}}; console.log(safe('xx-YY'))"
```

Expected: Unknown tags fall back to en-US instead of throwing.

### Step 4: Check the CMS or API that supplies the locale

```bash
grep -rn "locale" src/config.js | head -5
```

Expected: The source now emits hyphenated tags.

## When to use this

- formatjs or Intl throws RangeError about incorrect locale information
- Locale strings come from a CMS, URL param, or user profile

## When NOT to use this

- The date formats but in the wrong language, that is a missing locale-data issue
- You need a locale Intl does not know, load a polyfill with its data

## Tool and version compatibility

- formatjs v5/v6, all browsers with Intl, Node 13+
- BCP47 language tags, hyphens not underscores

## Variant phrasings

### same error from NumberFormat

Identical fix. All Intl constructors validate the tag the same way.

### locale with script subtag fails

Check the subtag order: language, script, region. zh-Hans-CN is right, zh-CN-Hans is not.

## Why it happens

Intl constructors validate the locale string against BCP47 before doing any formatting. Underscores, wrong subtag order, or unknown subtags fail validation, and formatjs just surfaces the RangeError from the constructor.

## Edge cases

- Lowercase region codes usually still work but canonical form is uppercase, normalize both
- Private-use subtags starting with x- are valid, do not strip them in normalization
- Some environments lack full ICU, a valid tag can still throw, check resolvedOptions

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_1btkDuu_srPdG5_ap5gCFg
