maotoumao/MusicFree · error · Error
'btoa' failed: The string to be encoded contains characters
Error message
'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.
What it means
The pure-JS btoa polyfill in src/utils/base64.ts throws this when any character code in the input string exceeds 0xFF (non-Latin1, e.g. Chinese text, emoji). Browser btoa has the same restriction; the polyfill replicates it. Input must be a binary/Latin1 string, not arbitrary UTF-8 text.
Source
Thrown at src/utils/base64.ts:21
// @flow
// Inspired by: https://github.com/davidchambers/Base64.js/blob/master/base64.js
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
const Base64 = {
btoa: (input: string = "") => {
let str = input;
let output = "";
for (
let block = 0, charCode, i = 0, map = chars;
str.charAt(i | 0) || ((map = "="), i % 1);
output += map.charAt(63 & (block >> (8 - (i % 1) * 8)))
) {
charCode = str.charCodeAt((i += 3 / 4));
if (charCode > 0xff) {
throw new Error(
"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.",
);
}
block = (block << 8) | charCode;
}
return output;
},
atob: (input: string = "") => {
let str = input.replace(/[=]+$/, "");
let output = "";
if (str.length % 4 == 1) {
throw new Error(
"'atob' failed: The string to be decoded is not correctly encoded.",
);View on GitHub (pinned to d118b18b3d)
Solutions
- Convert the string to UTF-8 bytes first: btoa(unescape(encodeURIComponent(str))) or use TextEncoder + manual base64.
- Better: add a utf8ToB64 helper in base64.ts that encodes via encodeURIComponent/unescape before the loop.
- If the payload is data, encode bytes (Uint8Array) instead of a JS string.
Example fix
// before const encoded = btoa(JSON.stringify(payload)); // after const encoded = btoa(unescape(encodeURIComponent(JSON.stringify(payload))));
Defensive patterns
Strategy: validation
Validate before calling
function isLatin1(str) {
for (let i = 0; i < str.length; i++) if (str.charCodeAt(i) > 0xff) return false;
return true;
}
if (!isLatin1(payload)) payload = unescape(encodeURIComponent(payload)); Try / catch
try {
return btoa(str);
} catch (e) {
if (String(e).includes('Latin1')) return btoa(unescape(encodeURIComponent(str)));
throw e;
} Prevention
- Never pass raw user text (Chinese, emoji) directly to btoa; UTF-8 encode first.
- Use a utf8ToB64/utf8SafeBtoa helper consistently across the codebase.
- For binary data, base64-encode Uint8Array bytes instead of JS strings.
- Add a unit test encoding a multilingual string.
When it happens
Trigger: Calling btoa(str) where str contains characters with code point > 255 — e.g. base64-encoding a JSON payload containing Chinese lyrics/titles, emoji, or any non-ASCII text.
Common situations: Encoding user-entered Chinese song names or config strings; encoding a UTF-8 string that was never percent-encoded or byte-converted first; porting browser code that assumed ASCII-only input.
Related errors
AI-assisted analysis of maotoumao/MusicFree@d118b18b3d (2026-08-30).
Data as JSON: /api/errors/4f9d5e7f66c092fe.
Report an issue: GitHub.