Documentación de Mentat — en evolución continua.
OperaciónTroubleshooting

Troubleshooting

Problemas conocidos y su solución. Si te topás con uno, no lo re-diagnostiques desde cero.

Build / frontend

SíntomaCausaSolución
Páginas sin estilos, chunks /_next/static/* en 404.next/ corrupto tras restartsrm -rf apps/web/.next, reinstalar, relanzar
next build falla con error de ESLint (“X is defined but never used”)next build corre next lint; tsc/dev no linteanpnpm --filter @mentat/web lint antes de deployar
”Cannot find module ’./NNN.js’” en otro navegadorse buildeó con el dev corriendo (comparten .next)bajar el dev, rm -rf .next, relanzar
Deploy de hosting sube bundle viejo / apuntando al emuladorel predeploy con --filter no matchea en Windows; sube el out/ previomover .env.local, rm -rf .next out, build a mano, deployar, restaurar

Functions

SíntomaCausaSolución
Deploy: “Cannot determine backend specification. Timeout after 10000”el predeploy no rebuildea (Windows) + discovery cortorebuild a mano + FUNCTIONS_DISCOVERY_TIMEOUT=120
package.json quedó minimizado tras un deploy fallidoel strip-script no llegó al restorenode apps/functions/scripts/strip-package-for-deploy.mjs restore
Emulador: “Failed to load function” en la 1ra llamadainestabilidad del Functions emulator en Windowsreiniciar emulador (matar puertos) + re-sembrar
Trigger: “Variable de entorno requerida ausente: FIREBASE_PROJECT_ID”el emulador setea GCLOUD_PROJECT, no FIREBASE_PROJECT_IDya resuelto con fallback en env.ts

Emulador / datos

SíntomaCausaSolución
”running multiple instances” / puerto ocupadoprocesos huérfanos de sesión anteriormatar PIDs de 4000/5001/8080/9099/9199/3000
Datos escritos pero no leídos (split-brain)emulador y cliente con distinto project IDalinear ambos a dawoork-mentat
”Cannot start Storage emulator without rules file”falta storage.rules en firebase.jsonya resuelto; verificar que existe

Producción / gcloud

SíntomaCausaSolución
Scripts admin: invalid_grant / invalid_raptADC vencidogcloud auth application-default login
API firebaserules da 403falta el quota projectheader X-Goog-User-Project: dawoork-mentat
Email no entrega a destinatarios realesdominio Resend sin verificar / MENTAT_FROM_EMAIL en sandboxverificar dominio + setear la env var + redeploy

Ingesta / DataSources

SíntomaCausaSolución
Subir CSV en /datasources → “Error inesperado.”uploadCsv (Storage) lanza un FirebaseError crudo que IngestionRunner no mapea → cae al fallback genéricoMirar el error real en la red (status del POST a firebasestorage.googleapis.com). Casi siempre es un 403 de las Storage Rules — ver abajo
Upload de CSV da 403 incluso siendo adminLas Storage Rules denegaban por el firestore.get cross-service (leer el rol) que no funciona en runtime de prodMitigado: el gate de rol se movió a la callable. Ver “Estado abierto”
La corrida de ingesta vuelve failed: N/N (todas las filas fallan)El object type que mapea el DataSource no existe en la ontología de esa orgCrear el/los object types referenciados por los mappings antes de ingestar. La org demo estaba sin ningún tipo (2026-06-09)
⚠️

Estado abierto (2026-06-09) — para retomar: El firestore.get cross-service en storage.rules (leer organizations/{orgId}/members/{uid}.role dentro de la regla de Storage) devuelve DENY en runtime de prod. Probado con bisect en vivo: un admin subiendo text/csv recibía 403; al reemplazar canUpload por isSignedIn() el mismo upload pasó a 200. Funciona en el emulador (por eso pasó los tests de Fase 5) pero no en prod — posible limitación con la edición de Firestore o el bucket .firebasestorage.app.

Mitigación viva: canUpload(orgId) quedó en isSignedIn() (gate interino: signed-in + path tenant-scoped + content-type/size). La autorización por rol real de la ingesta la hace la callable ingestDataSource (requireOrgRole), que además revalida que el path pertenezca a la org. La lectura de Storage sigue denegada. Riesgo: cualquier usuario autenticado podría escribir (no leer) un CSV en el prefijo de otra org; no puede disparar la ingesta de una org donde no tiene rol.

Pendiente de endurecer: mover el rol a custom claims del token (request.auth.token) para volver a un gate por rol en Storage sin depender del cross-service get. Requiere: función que mantenga los claims al cambiar membresías + backfill de los miembros existentes + re-login para refrescar el token. Decisión previa “sin custom claims” (referencia/security-rules) queda a revisar por este hallazgo.

Formularios / validación

SíntomaCausaSolución
”Datos inválidos — revisá: <campo>: <motivo>” al crear/editar (Action, Object, DataSource, etc.)El payload no pasó el Zod del borde; el mensaje nombra el campo y el motivo (ej. rules.0.targetType: requerido)Corregí ese campo. Para el shape de Actions ver Definir Actions; para Objetos/Ontología, Ontología

Desde 2026-06-10 el error de validación de las callables dejó de ser un genérico “Datos inválidos.” y lista los campos que fallaron (helper apps/functions/src/shared/validation-error.ts, usado por las 20 callables con borde Zod). El detalle completo (flatten) sigue viajando como details.

PowerShell (Windows)

SíntomaCausa
$org pisa $ORG (doc-id corrupto)las variables de PowerShell son case-insensitive — usá nombres distintos
Unexpected token '?'PowerShell 5.1 no tiene operador ternario — usá if/else
Comando bloqueado por contener /documents"el sandbox lo confunde con un borrado — partí el string