The Exact Error
DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
Quick summary:
btoa()can only encode characters in the Latin-1 range (codes 0-255). Any Unicode character above U+00FF ? emojis, Chinese characters, Arabic text, the euro sign ? triggers this error. The fix is to convert the string to UTF-8 bytes before encoding.
Why This Error Happens
btoa() (Binary To Ascii) treats each character as a single byte. Latin-1 maps one character to one byte, covering codes 0-255. Unicode characters above U+00FF don't fit in a single byte, so btoa() throws.
btoa('hello'); // 'aGVsbG8=' ? OK (all ASCII)
btoa('cafe'); // OK (all Latin-1)
btoa('?100'); // THROWS ? '?' is U+20AC, above U+00FF
btoa('Hello ??'); // THROWS ? emoji is above U+00FF
btoa('??'); // THROWS ? CJK characters above U+00FF
Step-by-Step Diagnosis
Step 1 ? Find the non-Latin-1 character
function findNonLatin1(str) {
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i);
if (code > 255) {
console.log(`Non-Latin1 at position ${i}: '${str[i]}' (U+${code.toString(16).toUpperCase()})`);
}
}
}
findNonLatin1('Hello ?100');
// Non-Latin1 at position 6: '?' (U+20AC)
Step 2 ? Determine what you're encoding
- Text content ? Use
encodeURIComponent+btoa - Binary data ? Use
Uint8Array?btoa - Node.js ? Use
Buffer
Solutions
Solution 1 ? Use encodeURIComponent before btoa
function base64Encode(str) {
return btoa(encodeURIComponent(str));
}
function base64Decode(str) {
return decodeURIComponent(atob(str));
}
const encoded = base64Encode('Hello ?? ?? ?100');
const decoded = base64Decode(encoded); // 'Hello ?? ?? ?100'
Solution 2 ? Use TextEncoder + Uint8Array
function base64EncodeUnicode(str) {
const bytes = new TextEncoder().encode(str);
const binString = Array.from(bytes, b => String.fromCodePoint(b)).join('');
return btoa(binString);
}
function base64DecodeUnicode(base64) {
const binString = atob(base64);
const bytes = Uint8Array.from(binString, c => c.codePointAt(0));
return new TextDecoder().decode(bytes);
}
Solution 3 ? Node.js Buffer approach
const encoded = Buffer.from('Hello ?? ??', 'utf8').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString('utf8');
Solution 4 ? URL-safe Base64
function base64UrlEncode(str) {
return btoa(encodeURIComponent(str))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
Quick Reference
| Scenario | Works with btoa()? | Fix |
|---|---|---|
| ASCII text only | Yes | Use directly |
| Latin-1 text (?, ?) | Yes (codes ?255) | Use directly |
| Euro sign ?, emojis | No (> U+00FF) | btoa(encodeURIComponent(str)) |
| Node.js server | N/A | Buffer.from(str, 'utf8').toString('base64') |
Prevent This Error in the Future
1. Never use bare btoa(text) for user-provided strings. Always use the encodeURIComponent wrapper.
2. Create helper functions once and reuse everywhere:
const b64encode = str => btoa(encodeURIComponent(str));
const b64decode = str => decodeURIComponent(atob(str));
3. In Node.js, use Buffer always ? it handles UTF-8 natively.
Use ToolNinja to Debug Faster
The Base64 tool handles Unicode encoding and decoding correctly ? paste any string including emojis, CJK characters, and accented text to get the correct Base64 output.