JavaScript isWellFormed and toWellFormed Explained
JavaScript strings use UTF-16 encoding, which occasionally results in
malformed strings containing unpaired surrogate code units. The
String.prototype.isWellFormed() and
String.prototype.toWellFormed() methods provide a native,
efficient way to check for and fix these ill-formed surrogate pairs.
This article covers why these methods exist, how they function, and how
to use them to prevent runtime errors in modern JavaScript
applications.
The Problem with Lone Surrogates in JavaScript
In UTF-16, characters outside the Basic Multilingual Plane (such as emojis or rare symbols) are represented using a pair of 16-bit code units known as a surrogate pair: a lead (high) surrogate followed by a trail (low) surrogate.
If a string contains a lead surrogate without a corresponding trail
surrogate—or vice versa—it is considered “ill-formed.” Passing an
ill-formed string to certain Web APIs (such as encodeURI()
or crypto.subtle.digest()) throws a URIError
or causes unexpected encoding behavior.
String.prototype.isWellFormed()
The isWellFormed() method returns a boolean indicating
whether a string is free of lone surrogates.
- Returns
trueif the string is valid UTF-16 and contains no lone surrogates. - Returns
falseif the string contains one or more unpaired surrogates.
// Well-formed strings
const text = "Hello, world!";
const emoji = "🚀"; // Valid surrogate pair: \uD83D\uDE80
console.log(text.isWellFormed()); // true
console.log(emoji.isWellFormed()); // true
// Ill-formed string with a lone surrogate
const loneSurrogate = "\uD83D"; // High surrogate without low surrogate
console.log(loneSurrogate.isWellFormed()); // falseString.prototype.toWellFormed()
The toWellFormed() method returns a new string where all
lone surrogates are replaced with the Unicode replacement character
U+FFFD (``). If the original string is already well-formed,
it returns a direct copy without modifications.
const badString = "User: \uD83D (invalid)";
const cleanString = badString.toWellFormed();
console.log(cleanString); // "User: (invalid)"
console.log(cleanString.isWellFormed()); // trueCommon Use Cases
- Preventing
encodeURIErrors: Functions likeencodeURI()fail immediately when encountering lone surrogates. Checking or sanitizing strings beforehand avoids uncaught exceptions.
function safeEncode(url) {
return encodeURI(url.toWellFormed());
}- Sanitizing Data for External APIs: Many database
drivers and foreign function interfaces (FFIs) expect strict UTF-8 text.
Using
toWellFormed()guarantees that data sent over the network or saved to disk conforms to Unicode standards.