BookinglyTech News
Software

btoa y atob siguen siendo latin1 y provocan mojibake en datos UTF-8

La función btoa/atob del navegador sigue operando con cadenas binarias en latin‑1, lo que hace que los caracteres fuera de U+00FF se codifiquen incorrectamente y generen errores silenciosos al decodificar.

2 min de lecturaDev.to0 vistas

btoa('café') devuelve Y2Fm6Q==, mientras que la versión correcta en UTF‑8 es Y2Fmw6k=. El problema se debe a que btoa y atob están diseñados para trabajar con "binary strings" donde cada carácter ocupa un byte. Si el carácter no cabe en un byte (por ejemplo, é = U+00E9), btoa la representa en latin‑1 (0xE9) y no en UTF‑8 (0xC3 0xA9). El resultado es que la cadena decodificada con atob produce mojibake, pero sin lanzar error.

¿Qué pasa con los errores?

  • Codificación: Si el carácter excede U+00FF, btoa lanza InvalidCharacterError. Los emojis y los textos CJK fallan de inmediato.
  • Decodificación: atob nunca lanza error; simplemente devuelve la secuencia de bytes y el resto del proceso interpreta esos bytes como si fueran UTF‑8, produciendo caracteres extraños.

Solución recomendada

Para evitar estos problemas, convierta explícitamente el texto a bytes UTF‑8 antes de usar btoa y decodifique con un TextDecoder configurado como fatal:

const UTF8_ENCODE = new TextEncoder();
const UTF8_DECODE = new TextDecoder('utf-8', { fatal: true });

function encodeBase64(text) {
  const bytes = UTF8_ENCODE.encode(text);
  const CHUNK = 0x8000;
  let binary = '';
  for (let i = 0; i < bytes.length; i += CHUNK) {
    binary += String.fromCharCode.apply(null, bytes.subarray(i, i + CHUNK));
  }
  return btoa(binary);
}

function decodeBase64(b64) {
  const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
  return UTF8_DECODE.decode(bytes);
}

Puntos clave

  • fatal: true hace que el decoder lance error ante bytes inválidos, evitando que se devuelvan sustitutos.
  • No se debe usar String.fromCharCode(...bytes) con arreglos grandes; el límite de la pila varía entre motores.
  • Se recomienda aceptar ambos alfabetos de base64 (RFC 4648 §4 y §5) y usar TextDecoder para detectar caracteres no válidos.

Por qué importa

Muchas aplicaciones, especialmente aquellas que generan tokens JWT o comunican datos entre servicios, confían en btoa/atob sin considerar el soporte UTF‑8. Cuando los datos se persisten en bases de datos o se transmiten a sistemas externos, el mojibake puede propagarse y causar errores difíciles de rastrear. Al implementar la solución propuesta, los equipos garantizan que la codificación y decodificación de base64 sea consistente y segura, evitando pérdidas de datos y fallos silenciosos en producción.


En resumen, btoa y atob siguen siendo herramientas legacy de latin‑1. Para trabajar con UTF‑8, convierta el texto a bytes explícitamente y use un decoder fatal para detectar errores. Así se evita la propagación de mojibake y se mantiene la integridad de los datos en entornos modernos.