Los mensajes de error de un vistazo
| Mensaje | Dónde lo ves | Causa más probable |
|---|---|---|
binascii.Error: Incorrect padding | base64.b64decode de Python | Faltan = al final, a menudo por Base64URL o una cadena cortada |
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4 | Python | Entrada truncada, o -/_ descartados sin avisar |
binascii.Error: Only base64 data is allowed | Python con validate=True | Salto de línea, espacio, - o _ en la entrada |
InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded. | Chrome, Edge | Caracteres Base64URL, caracteres basura, longitud incorrecta |
InvalidCharacterError: String contains an invalid character | Firefox | Lo mismo que arriba |
InvalidCharacterError: Invalid character | atob de Node.js | Lo mismo que arriba |
IllegalArgumentException (“Illegal base64 character …”) | java.util.Base64 de Java | Decodificador que no corresponde al alfabeto, o saltos de línea |
FormatException | Convert.FromBase64String de .NET | Caracteres Base64URL o falta de relleno |
base64: invalid input | base64 -d de GNU coreutils | Caracteres fuera del alfabeto |
Cómo solucionar los errores del decodificador
«Incorrect padding» en Python
La salida Base64 siempre tiene una longitud múltiplo de 4, rellenada con = al final. El decodificador de Python exige el relleno:
>>> import base64
>>> base64.b64decode("SGVsbG8")
Traceback (most recent call last):
...
binascii.Error: Incorrect padding
>>> base64.b64decode("SGVsbG8=")
b'Hello'
La falta de relleno suele significar que la cadena es Base64URL (los JWT, los tokens en URL y muchas API omiten el =) o que algo la recortó. Vuelve a añadir el relleno:
s = "SGVsbG8"
s += "=" * (-len(s) % 4)
Cuando la longitud es uno más que un múltiplo de 4, el relleno no sirve de nada. Python informa entonces de number of data characters (5) cannot be 1 more than a multiple of 4. Un solo carácter sobrante contiene solo 6 bits, así que falta parte de los datos. Este mensaje también puede aparecer sin que la cadena esté truncada: sin validate=True, Python descarta los caracteres fuera del alfabeto, incluidos - y _. base64.b64decode("SGk_Pg==") elimina el _ y se queda con 5 caracteres de datos. Usa base64.urlsafe_b64decode para las entradas Base64URL.
«Invalid character» y fallos de atob
Los navegadores implementan atob con el mismo algoritmo, pero redactan el error de forma distinta. Chrome dice «The string to be decoded is not correctly encoded», Firefox dice «String contains an invalid character» y Node.js dice «Invalid character». Los tres lanzan un InvalidCharacterError con estas entradas:
- Caracteres Base64URL.
atob("SGk_Pg")falla por el_. Sustituye antes-por+y_por/. - Una longitud de 4n+1 después de quitar los espacios en blanco, como en
atob("A"). - Caracteres que no pintan nada ahí: comillas copiadas de un JSON, un prefijo
data:, un%2Fde la codificación de URL.
atob sí perdona algunas cosas. Se salta espacios y saltos de línea, y acepta la falta de relleno cuando la longitud cuadra, así que atob("SGVsbG8") devuelve "Hello". El error inverso, btoa fallando con «characters outside of the Latin1 range», tiene que ver con el texto Unicode y se explica en Uint8Array.toBase64.
Un decodificador tolerante que admite los dos alfabetos, espacios en blanco y falta de relleno:
function decodeLoose(s) {
s = s.replace(/\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");
s += "=".repeat((4 - (s.length % 4)) % 4);
return Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
}
new TextDecoder().decode(decodeLoose("SGk_Pg")); // "Hi?>"
El equivalente en Python:
import base64
def b64decode_any(s: str) -> bytes:
s = "".join(s.split())
s = s.replace("-", "+").replace("_", "/")
s += "=" * (-len(s) % 4)
return base64.b64decode(s, validate=True)
La herramienta Reparar Base64 aplica la misma limpieza y te dice qué ha cambiado.
«Illegal base64 character» en Java y FormatException en .NET
java.util.Base64 de Java trae tres decodificadores, y cada uno es estricto con su propio alfabeto. El mensaje indica el carácter problemático en hexadecimal: 5f es _, 2d es -, 2f es /, 20 es un espacio y a es un salto de línea.
| La entrada contiene | Usa |
|---|---|
+ y / | Base64.getDecoder() |
- y _ | Base64.getUrlDecoder() |
| Saltos de línea (MIME, cuerpos PEM) | Base64.getMimeDecoder() |
El decodificador básico rechaza los saltos de línea y los espacios. Sí acepta la falta de relleno, así que SGVsbG8 se decodifica sin quejas.
Convert.FromBase64String de .NET lanza FormatException con caracteres Base64URL y cuando falta el relleno. Se salta los espacios y los saltos de línea. Corrige el alfabeto y el relleno como se muestra arriba antes de llamarlo. Consulta Base64 en Java y Base64 en C# para ver ejemplos completos.
El texto sale ilegible
La decodificación ha funcionado, pero el texto se ve mal. Base64 guarda bytes, y esos bytes se generaron a partir de un texto con una codificación de caracteres concreta. Si los lees con otra distinta, obtienes mojibake.
| Ves | Original | Qué ha pasado |
|---|---|---|
Café | Café | Bytes UTF-8 leídos como Latin-1 o Windows-1252 |
Caf� | Café | Bytes Windows-1252 leídos como UTF-8 |
H e l l o o H\0e\0l\0l\0o\0 | Hello | Bytes UTF-16LE leídos como UTF-8 |
La primera fila es la trampa clásica de atob. atob("Q2Fmw6k=") devuelve "Café", porque atob asigna un carácter a cada byte. Decodifica los bytes como UTF-8:
const bytes = Uint8Array.from(atob("Q2Fmw6k="), (c) => c.charCodeAt(0));
new TextDecoder().decode(bytes); // "Café"
UTF-16LE es habitual con las herramientas de Windows: el -EncodedCommand de PowerShell y muchas API de .NET lo generan. Base64 a texto te deja cambiar el juego de caracteres hasta que la salida se lea bien, y Base64 a UTF-16 se ocupa del caso de caracteres anchos.
La salida parece binaria
Si el resultado decodificado está lleno de �, caracteres de control o fragmentos como PNG, PK y %PDF, el contenido es un archivo. Mira los primeros caracteres del Base64: iVBORw0KGgo es un PNG, JVBERi0 un PDF y H4sI gzip. La lista completa está en prefijos Base64 habituales. Abre los datos con Base64 a archivo, que detecta el formato y ofrece la descarga. Para H4sI, usa decodificar gzip en Base64.
La decodificación da bytes distintos de los esperados
No hay error, pero los bytes no son los correctos. Estas son las razones habituales:
- Un salto de línea final al codificar.
echo "hello" | base64daaGVsbG8K(con\n), mientras queecho -n "hello" | base64daaGVsbG8=. Usaprintf '%s'oecho -n. - El
+convertido en espacio. En las query strings de las URL y en los cuerpos de formulario,+significa espacio.URLSearchParams("t=PGI+Ym9sZDwvYj4=").get("t")devuelvePGI Ym9sZDwvYj4=. Algunos decodificadores lanzan entonces un error y otros descartan el espacio y producen basura. Codifica el Base64 conencodeURIComponentantes de meterlo en una URL, o usa Base64URL. - Codificación porcentual sin deshacer.
SGk%2FPg%3D%3Ddebe decodificarse como URL, quedandoSGk/Pg==, antes de decodificar el Base64. - Escapes copiados de un JSON. Copiar una cadena de un JSON en bruto puede arrastrar un
\nliteral (dos caracteres). El decodificador tolerante de Python descarta la barra invertida, se queda con lany devuelve bytes incorrectos sin ningún error:b64decode("SGVs\\nbG8=")dab'Hel\x9d\xb1\xbc'. Analiza el JSON en lugar de copiar de él. El decodificador Base64 para JSON lo hace con todos los campos. - Espacios en blanco: estricto frente a tolerante. Python sin
validate=True,atob, .NET y el decodificador MIME de Java se saltan los saltos de línea. Python convalidate=Truey el decodificador básico de Java los rechazan. Los datos MIME y PEM vienen cortados a 76 o 64 caracteres, así que elige un decodificador que los acepte.
Datos codificados dos veces
Al decodificar U0dWc2JHOGdkMjl5YkdRaA== se obtiene SGVsbG8gd29ybGQh, que vuelve a ser Base64 válido y se decodifica como Hello world!. Cuando el resultado de una decodificación está formado solo por caracteres Base64 y su longitud es múltiplo de 4, sospecha de una doble codificación.
Ocurre a menudo con los Secrets de Kubernetes. Los valores bajo data: están en Base64, y kubectl create secret --from-literal los codifica por ti. Si codificas tú antes el valor, el pod recibe texto Base64 en lugar de la contraseña. Usa stringData: para los valores en claro, o comprueba lo que hay guardado con el decodificador de Secrets de Kubernetes. Si tienes dudas, el validador Base64 indica si una cadena es válida y cuántos bytes contiene.
Preguntas frecuentes
¿Cómo soluciono binascii.Error: Incorrect padding?
Añade = hasta que la longitud sea múltiplo de 4: s += "=" * (-len(s) % 4). Si la cadena es Base64URL, sustituye además - por + y _ por /, o usa base64.urlsafe_b64decode.
¿Por qué atob falla con un JWT?
Los JWT usan Base64URL, que tiene - y _. atob solo conoce + y /. Convierte antes los caracteres o pega el token en el decodificador JWT.
¿Por qué el texto decodificado muestra é en lugar de é?
Los bytes son UTF-8, pero se leyeron como Latin-1 o Windows-1252. Decodifica los bytes como UTF-8, por ejemplo con TextDecoder en JavaScript o .decode("utf-8") en Python.
¿Se puede reparar una cadena Base64 de longitud 4n+1?
No. Un carácter sobrante solo lleva 6 bits, menos de un byte, así que falta al menos un carácter. Busca la fuente original o comprueba dónde se cortó la cadena.
¿Cómo sé si unos datos se codificaron en Base64 dos veces?
Decodifícalos una vez. Si el resultado vuelve a ser una cadena formada solo por A-Z a-z 0-9 + / = con una longitud múltiplo de 4, decodifícala otra vez.