Ir al contenido

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.

Al iniciar sesión aparece:

Error de permisos en el log

There is no existing directory at "/usr/share/histrix/database/{base}/log/{año}/{mes}"
and it could not be created: Permission denied

Los 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.

Ventana de terminal
cd /usr/share/histrix/database/{base}/log
chmod 777 .
mkdir -p 2026/01
chmod 777 2026 2026/01

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:

Ventana de terminal
composer dumpautoload

En una instalación con Docker el comando corre dentro del contenedor:

Ventana de terminal
docker exec -it histrix composer dumpautoload

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:

Ventana de terminal
sudo systemctl restart apache2

En Docker:

Ventana de terminal
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:

  1. Falta un archivo de vendor declarado en el bundle. El de CSS falla con 500 y el de JavaScript se genera sin jQuery.
  2. 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.

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.

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.

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.

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.

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.