El error r.map is not a function del panel de Jellyfin 12 aparece cuando la petición /web/ConfigurationPages recibe HTML o un cuerpo vacío en lugar de una lista JSON, y no se va al arreglar el proxy porque el navegador guarda esa respuesta. La interfaz web la conserva en IndexedDB hasta 24 horas, y si tu proxy servía HTML, también en la caché HTTP. Lo reproduje el 18 de octubre de 2026 con Jellyfin 12.2.0 en Docker, nginx 1.29.8 y Chrome for Testing 155. Esta guía muestra cómo comprobar tu proxy, qué cambiar en nginx, qué borrar en el navegador y qué atajos del hilo no me funcionaron. Tienes la versión en inglés de esta guía.

Puntos clave

  • El fallo sale de una línea del menú lateral del panel: llama a .map() sobre la respuesta de /web/ConfigurationPages, y una cadena de texto no tiene ese método.
  • Reproduje el error exacto de dos formas: con un nginx que sirve /web/ desde disco y devuelve index.html, y con una respuesta 200 vacía.
  • Tras corregir nginx, el panel siguió roto: el componente falla antes de pedir datos nuevos, así que la respuesta mala no se reemplaza.
  • Funcionó vaciar la caché HTTP del navegador y borrar la clave jellyfin-query-cache de IndexedDB; cada paso por separado no bastó.
  • A 28 de octubre de 2026, las incidencias jellyfin#17989 y jellyfin-web#8190 siguen abiertas y ni la 12.3 ni la 12.4 traen un arreglo.

¿Qué significa r.map is not a function en el panel de Jellyfin?

Significa que el código del panel recibió texto donde esperaba una lista. Al abrir el panel de control, el navegador pinta esta página en lugar del menú, con la misma traza que publicaron los afectados en la incidencia 17989 de Jellyfin[1]:

Unexpected Application Error!
r.map is not a function

TypeError: r.map is not a function
    at he (http://127.0.0.1:30700/web/6496.59e71d86fcea8244ef07.chunk.js:1:8319)
    at hu (http://127.0.0.1:30700/web/node_modules.react-dom.bundle.js?...)

La r es el nombre que el empaquetador dio a una variable al minimizar el código, y por eso otros usuarios ven j.find is not a function o u.forEach is not a function con el mismo origen. En el código de jellyfin-web, la variable es la respuesta de los complementos con página de ajustes en el menú, y el componente PluginDrawerSection la recorre así:

const { data: pagesInfo } = useConfigurationPages({ enableInMainMenu: true });

{pagesInfo?.map(pageInfo => (
    <ListItemLink key={pageInfo.PluginId} /* ... */ />
))}

El operador ?. protege contra null y undefined, pero no contra una cadena. Si la respuesta es el HTML de la página de inicio o la cadena vacía "", pagesInfo.map no existe y React tumba toda la ruta del panel.

¿Por qué la respuesta llega como HTML o vacía?

Porque algo entre el navegador y Jellyfin contesta en su lugar. La ruta /web/ConfigurationPages cuelga de /web/, igual que los ficheros estáticos de la interfaz, aunque la sirve la API del servidor. Si tu proxy sirve /web/ desde disco con un try_files que cae en index.html, esa petición recibe HTML. Así quedó en mi laboratorio:

location /web/ {
    alias /srv/jellyfin-web/;
    try_files $uri $uri/ /web/index.html;
}

Con ese bloque, la petición del panel devolvió 200 text/html y el panel cayó con la traza de arriba. La segunda forma que reproduje fue un proxy que contesta 200 con el cuerpo vacío: el cliente guardó "" como dato y falló igual. Un participante del hilo encontró exactamente esa cadena vacía en su caché, junto a otras tres consultas del panel. No sé qué proxy o red le devolvió el cuerpo vacío, y nadie del hilo lo ha aislado.

¿Por qué sigue fallando después de arreglar el proxy?

Porque desde la 12.0 la interfaz web guarda en el navegador las respuestas de la API. Las notas de la versión 12.0[2] lo anuncian así: "Add caching of queries to indexed db for the tanstack query client for improved loading performance". En el código, esa caché vive en la base de IndexedDB keyval-store, bajo la clave jellyfin-query-cache, y conserva cada consulta hasta 24 horas.

Lo comprobé cambiando nginx a una configuración correcta con el panel ya roto. El servidor respondía JSON, pero el navegador ni siquiera repitió la petición: el componente falla al pintarse, antes de que la consulta se renueve, y el dato malo vuelve a cargarse en cada visita. Si tu proxy servía HTML, hay una segunda trampa: nginx mandó ese index.html con Last-Modified y sin Cache-Control, y Chrome lo guardó en su caché HTTP. Al borrar solo IndexedDB, la nueva petición recibió otra vez el HTML desde el disco.

Cómo comprobar si tu proxy devuelve HTML en /web/ConfigurationPages

Pide esa ruta sin credenciales: Jellyfin debe contestar 401 y tu proxy no debe cambiarlo. Este curl imprime el código y el tipo de contenido:

curl -s -o /dev/null -w '%{http_code} %{content_type}\n' \
  'https://tu_dominio_jellyfin/web/ConfigurationPages?enableInMainMenu=true'

En mi laboratorio, el nginx correcto devolvió 401 sin tipo de contenido. El nginx que servía /web/ desde disco devolvió 200 text/html, la señal del fallo. Con sesión iniciada, una respuesta sana es 200 application/json con [] si no tienes complementos con página en el menú. Si ves 401, revisa también la guía para instalar Jellyfin con Docker y compara tu proxy con el suyo.

Arreglo 1: que nginx deje pasar /web/ConfigurationPages a Jellyfin

La solución de fondo es no servir /web/ desde disco: la guía de nginx de Jellyfin[3] manda todo a Jellyfin con un único location /. Si quieres seguir sirviendo los estáticos, saca de ese bloque las dos rutas de la API que cuelgan de /web/. Esta expresión regular cubre ConfigurationPages y ConfigurationPage:

location ~ ^/web/ConfigurationPages?$ {
    proxy_pass http://jellyfin:8096;
    proxy_set_header Host $host;
}

Ponlo en el mismo server que el location /web/ anterior; nginx da prioridad a las expresiones regulares sobre los prefijos. Con este bloque, la petición devolvió 200 application/json y un perfil de navegador nuevo abrió el panel sin error. Si usas Caddy o Traefik con los estáticos en disco, aplica la misma exclusión; no lo probé en ellos.

Arreglo 2: borrar jellyfin-query-cache y la caché del navegador

Con el proxy ya corregido, vacía primero la caché HTTP de tu dominio de Jellyfin y después la clave de IndexedDB. En Chrome, la primera está en Borrar datos de navegación, con la casilla de imágenes y archivos en caché. Yo la vacié con la orden equivalente del protocolo de depuración de Chrome, Network.clearBrowserCache.

Para la segunda, cierra las pestañas de Jellyfin y abre https://tu_dominio_jellyfin/web/config.json, que es del mismo origen pero no arranca la aplicación. Pega esto en la consola de las herramientas de desarrollo:

const r = indexedDB.open('keyval-store');
r.onsuccess = () => {
  const tx = r.result.transaction('keyval', 'readwrite');
  tx.objectStore('keyval').delete('jellyfin-query-cache');
  tx.oncomplete = () => console.log('jellyfin-query-cache borrada');
};

El código abre la base keyval-store, borra solo la clave de la caché de consultas y avisa en la consola. No toca tu sesión, que vive en localStorage. Si prefieres no usar la consola, en la pestaña Application de Chrome, o Almacenamiento en Firefox, despliega IndexedDB, entra en keyval-store y borra la fila jellyfin-query-cache.

Lo hice desde config.json porque desde el panel roto no funcionó: borré la clave con la aplicación abierta, recargué y la caché volvía a tener el HTML. Con las dos cachés vacías, el panel pidió /web/ConfigurationPages, recibió JSON y cargó.

¿Sirven las cabeceras WebSocket o abrir /web/#/dashboard?

En mi laboratorio no arreglaron un panel ya roto, aunque dos usuarios del hilo dicen que las cabeceras les funcionaron. Probé cada atajo que aparece en las dos incidencias sobre el mismo perfil de Chrome con la caché envenenada:

Qué probé Resultado en mi laboratorio
Abrir /web/#/dashboard directamente sigue fallando
Añadir Upgrade y Connection a nginx sigue fallando
Vaciar solo la caché HTTP sigue fallando
Cerrar sesión y volver a entrar sigue fallando
Borrar solo jellyfin-query-cache, con el proxy que servía HTML sigue fallando
Vaciar la caché HTTP y borrar la clave funciona
Perfil de navegador nuevo, como una ventana privada funciona

Sin las cabeceras WebSocket, el /socket de Jellyfin respondió 404 y la consola mostró 9 intentos de conexión fallidos, pero el panel cargó bien con un perfil limpio. Mantén las cabeceras de todos modos, porque las actualizaciones en vivo del panel dependen de ellas. Este es el bloque que dejé, con las cabeceras que también activa el interruptor de WebSockets de Nginx Proxy Manager:

location / {
    proxy_pass http://jellyfin:8096;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
}

Lo de la ventana privada encaja con lo que contó otro afectado, al que le fallaba Firefox 157 pero no una ventana privada: un perfil limpio no tiene la respuesta mala guardada. Si tu proxy sigue respondiendo mal, el error vuelve en cuanto el navegador la guarde otra vez.

¿Hay ya un arreglo en Jellyfin 12?

No, a 28 de octubre de 2026. La incidencia jellyfin#17989[1] se abrió el 11 de septiembre, sigue abierta con la etiqueta de fallo y figura como pendiente de pruebas en el tablero del proyecto. El colaborador fma-rc la señaló como duplicada de jellyfin-web#8190[4], abierta el 10 de julio con una compilación inestable posterior a la 12.0-rc2. Esa otra se cerró como descartada el 10 de septiembre y se reabrió el 13.

En el hilo se propone comprobar con Array.isArray que la respuesta sea una lista antes de recorrerla, pero no hay ninguna solicitud de cambio enlazada en jellyfin-web. Las únicas confirmaciones que citan el fallo están en un fork ajeno al proyecto, del 13 de octubre. La 12.3, del 23 de octubre, y la 12.4, del 26, no tocan ese código. La rama principal de jellyfin-web suma 278 confirmaciones desde la etiqueta v12.2 y useConfigurationPages.ts sigue igual que en la 12.2 publicada el 5 de octubre.

Hay un detalle del código que juega a tu favor al actualizar: la caché se descarta cuando cambia la versión de compilación de la interfaz, como explica la documentación de persistQueryClient[5]. Si sigues la guía para actualizar Jellyfin 12 con Docker, la respuesta mala no sobrevivirá al cambio de versión. No lo he probado: mi laboratorio es de la 12.2 y no he repetido la actualización a la 12.4.

Preguntas frecuentes

¿Pierdo algo al borrar jellyfin-query-cache?

No pierdes datos del servidor. La clave solo guarda copias de respuestas de la API para que la interfaz cargue antes, y se rellena sola al navegar. En mi prueba, la sesión siguió iniciada después de borrarla.

¿Por qué funciona con la IP y el puerto pero no con mi dominio?

Porque cada origen tiene su propia caché en el navegador. Si entras por http://ip:8096, ni la petición pasa por el proxy ni se lee la caché guardada para tu dominio. El primer informe de la incidencia 17989 describe justo eso con Cloudflare Tunnel y Caddy.

¿Me afecta si no uso complementos?

Sí. En mi laboratorio no había ningún complemento instalado y el panel falló igual, porque el menú hace la petición siempre. Con el servidor sano, la respuesta es una lista vacía, [], y el panel carga sin problema.

Conclusión

r.map is not a function en Jellyfin 12 tiene dos partes: una respuesta que no es JSON en /web/ConfigurationPages y una caché que la conserva. Comprueba con curl que tu proxy devuelve 401 sin credenciales, saca esa ruta de cualquier bloque que sirva /web/ desde disco y luego vacía la caché HTTP y la clave jellyfin-query-cache. Revisa la incidencia 17989 antes de tu próxima actualización: cuando llegue la comprobación de tipo, el panel dejará de caerse aunque el proxy falle, pero el proxy seguirá necesitando el arreglo.

Fuentes: [1] Jellyfin, incidencia 17989 sobre r.map is not a function[1], [2] jellyfin-web, incidencia 8190[4], [3] Jellyfin, notas de la versión 12.0[2], [4] jellyfin-web, PluginDrawerSection.tsx[6], [5] jellyfin-web, queryClient.ts[7], [6] Jellyfin, DashboardController.cs[8], [7] Documentación de Jellyfin, proxy inverso con nginx[3], [8] Nginx Proxy Manager, plantilla proxy_host.conf[9], [9] TanStack Query, persistQueryClient[5].

Fuentes

  1. incidencia 17989 de Jellyfin
  2. notas de la versión 12.0
  3. guía de nginx de Jellyfin
  4. jellyfin-web#8190
  5. documentación de persistQueryClient
  6. jellyfin-web, PluginDrawerSection.tsx
  7. jellyfin-web, queryClient.ts
  8. Jellyfin, DashboardController.cs
  9. Nginx Proxy Manager, plantilla proxy_host.conf