Problemas frecuentes
Cada entrada parte del síntoma observable, porque es lo único que se tiene al principio. La regla general es diagnosticar antes de editar: pedir el error real de la consola del navegador, el log del servidor web o el SQL generado, y recién entonces corregir.
Errores de permisos en los logs
Sección titulada «Errores de permisos en los logs»Al iniciar sesión aparece:

There is no existing directory at "/usr/share/histrix/database/{base}/log/{año}/{mes}"and it could not be created: Permission deniedLos logs se organizan por año y mes, y el directorio del mes se crea al vuelo. Cuando el proceso web no tiene permiso de escritura, el primer acceso de cada mes falla.
cd /usr/share/histrix/database/{base}/logchmod 777 .mkdir -p 2026/01chmod 777 2026 2026/01Class 'NombreDeLaClase' not found
Sección titulada «Class 'NombreDeLaClase' not found»El XML se ejecuta pero no hace nada de lo que define su dataSource, o la request falla
con ese error. Las clases se cargan por classmap de Composer, y el mapa quedó
desactualizado tras crear, mover o renombrar la clase:
composer dumpautoloadEn una instalación con Docker el comando corre dentro del contenedor:
docker exec -it histrix composer dumpautoloadUn cambio en un XML no se ve
Sección titulada «Un cambio en un XML no se ve»Histrix reparsea los XML en cada request: los cambios se ven recargando la página con
Ctrl+F5. No hace falta limpiar OPcache ni reiniciar el servidor web.
Lo que sí tiene caché son los bundles de JavaScript y CSS. En una instalación con
Apache y PrivateTmp, el caché no está en /tmp/histrix/ del host, así que borrar ese
directorio no tiene efecto; hay que reiniciar el servicio:
sudo systemctl restart apache2En Docker:
docker exec histrix sh -c 'rm -rf /tmp/histrix/*'jQuery is not defined, o CSS que llega como text/html
Sección titulada «jQuery is not defined, o CSS que llega como text/html»Las respuestas de /api/js/{db} o /api/css/{db} vienen con el tipo MIME equivocado o
incompletas. Son dos causas que suelen darse juntas:
- Falta un archivo de vendor declarado en el bundle. El de CSS falla con 500 y el de JavaScript se genera sin jQuery.
- El caché de Assetic quedó guardado con el resultado roto.
Se corrige quitando del bundle el archivo faltante y borrando el caché de assets del contenedor o reiniciando el servicio web.
El menú aparece vacío
Sección titulada «El menú aparece vacío»GET /api/db/{db}/menu/ devuelve HTTP 200 con tree: [].
Antes de revisar permisos de perfil, mirar parameters.login en la respuesta: si viene
vacío, el token es válido pero no tiene un usuario asociado, y el menú se arma vacío sin
emitir error.
Si el login sí está presente, el motivo habitual es que los ítems de HTXMENU no tengan
web_version = 1. Al actualizar una instalación anterior a mayo de 2026 hay que
asignarlo.
Login con error 500 para todos los usuarios
Sección titulada «Login con error 500 para todos los usuarios»Falta la columna HTXPROFILES.realm, que el login usa para validar por qué canal puede
entrar cada perfil. Como afecta también al administrador, no se puede corregir desde la
interfaz: hay que agregar la columna directamente en la base. Ver
Autenticación y OIDC.
401 con usuario y contraseña correctos
Sección titulada «401 con usuario y contraseña correctos»El realm que se le exige al usuario sale del primer valor de oauth_clients.scope. Si
ese campo empieza con algo distinto de web —por ejemplo openid web offline_access—
el login pide un realm que ningún perfil declara y falla en silencio. El orden correcto
es web openid offline_access.
403 en .well-known/openid-configuration o jwks.json
Sección titulada «403 en .well-known/openid-configuration o jwks.json»Los endpoints de descubrimiento OIDC no están en la raíz del sitio sino bajo
/api/db/{db}/. Varios proxies traen reglas que solo permiten .well-known en la raíz.
El problema está en el proxy inverso, no en Histrix.
500 en jwks.json, userinfo o authorize
Sección titulada «500 en jwks.json, userinfo o authorize»El par de claves RSA de la base tiene el propietario equivocado. Las claves de
database/.oidc/{db}/ las tiene que generar el proceso que atiende el sitio (php-fpm o
Apache); si se pre-generaron desde la línea de comandos como root, hay que corregir el
propietario.
Un mismo XML se comporta distinto en dos bases
Sección titulada «Un mismo XML se comporta distinto en dos bases»Las dos bases resuelven archivos distintos. Comparar el parámetro CONFIG::baseModule
de cada una y el contenido de sus respectivos xmlPath: un XML propio de la base
sobrescribe por completo al del módulo, y un override desactualizado se rompe en
silencio cuando el módulo evoluciona. Ver Arquitectura.
Un campo queda vacío y la grabación no ocurre
Sección titulada «Un campo queda vacío y la grabación no ocurre»Si el campo depende de un <if>, revisar que todos los identificadores que la expresión
menciona estén declarados como <field> en el XML. Un identificador no declarado se
evalúa como constante indefinida, el resultado queda nulo y se toma la rama falsa sin
ningún mensaje de error. Si ese campo se usa además como idCampoCond, el registro no
se graba.
Un valor de fecha se graba como 0000-00-00
Sección titulada «Un valor de fecha se graba como 0000-00-00»setFieldValue no evalúa funciones SQL: pasar 'now()' como string a un campo de tipo
entero graba una fecha nula sin emitir error y sin que se note en las lecturas
posteriores. El valor hay que calcularlo en PHP antes de asignarlo.
Al elegir una fila de un popup de ayuda no se llena el campo
Sección titulada «Al elegir una fila de un popup de ayuda no se llena el campo»El click marca la fila pero el valor no vuelve al formulario. Las filas de la ayuda
necesitan un campo clave para poder identificar el destino; cuando la grilla está sobre
una vista de MySQL, el motor no puede descubrir la clave primaria por introspección.
Declarar explícitamente esClave="true" en el campo identificador de la ayuda.
Un popup de ayuda devuelve cero filas desde un cliente propio
Sección titulada «Un popup de ayuda devuelve cero filas desde un cliente propio»Las ayudas se sirven desde la instancia del formulario padre, no pidiendo el XML de la ayuda por separado:
POST /api/db/{db}/instance/{instance}/field/{field}/help/Esa ruta aplica las condiciones que el padre le impone al helper. Pedir el XML por
app/ ignora esas condiciones.