Skip to main content

Troubleshooting

Troubleshooting

Dernière mise à jour : 2026-05-10

Pièges connus déjà rencontrés, à actualiser au fil des incidents.

Build / CI

Le job test échoue avec une erreur better-sqlite3

  • Cause : tu as changé l'image de base CI vers Alpine. Pas de prebuild musl pour better-sqlite3.
  • Fix : remettre node:22-bookworm-slim (Debian Slim glibc).

vue-tsc --noEmit passe en local mais foire en CI

  • Cause : la CI fait vue-tsc --build (compile full), pas --noEmit (type-check seul).
  • Fix : tester avec npm run build (qui appelle vue-tsc --build) avant de push.

Backend runtime

Boolean("false") === true — env var qui ne fait pas ce qu'on attend

  • Symptôme : VISION_ENABLED=false est interprété comme true.
  • Cause : z.coerce.boolean() en JS — toute chaîne non vide est truthy.
  • Fix : utiliser le helper envBool() défini en haut de src/config.ts. Comprend true/false/1/0/yes/no/on/off.

process.env.X retourne undefined en prod

  • Cause : la var n'a pas été ajoutée dans unraid/boardgame-referee.xml, donc l'admin Unraid ne l'a pas setée dans l'UI.
  • Fix : règle des 3 fichiers — src/config.ts + .env.example + unraid/boardgame-referee.xml. Sinon la var est silencieusement absente.

Une regex \b ne match pas un nom finissant par é

  • Cause : \b sans flag u ne reconnaît que les boundaries [A-Za-z0-9_].
  • Fix : lookahead Unicode-aware avec flag u : (?=\\s|$|[^\\p{L}\\p{N}_]). Piège historiquement déclenché sur les mentions @ Lorcana.

Claude répond "je ne vois aucune image"

  • Cause : claude-ssh.ts lance le CLI avec --system-prompt au lieu de --append-system-prompt. Le contrat d'utilisation des outils est écrasé.
  • Fix : toujours --append-system-prompt.

ClaudeQuotaError non détectée → "answer empty" générique

  • Cause : le wording du message de quota a changé côté Anthropic.
  • Fix : étendre QUOTA_MARKERS dans claude-quota.ts. Cf. pipeline-rag/pause-quota-claude.md.

Retrieval / RAG

Citation [BASE p.4 : "..."] ouvre la mauvaise page

  • Cause : plusieurs livrets indexés partagent la page 4 (base + extension). La regex de citation ne capturait pas le nom du livret.
  • Fix : cf. ARCHITECTURE.md § "Citations cliquables — format nom du livret". Le format est désormais [<nom du livret>, p.X : "..."] avec résolution nameToId côté frontend.

Image PNG envoyée à Claude mais c'est la page 4 du mauvais livret

  • Cause : groupage par page au lieu de (livret, page) dans answer.ts.
  • Fix : cf. pipeline-rag/vision-inline.md — granularité composite obligatoire.

Claude cite un livret en [EXT p.4] au lieu de [Heavy Rain, p.4]

  • Cause : ancien format de citation pré-2026-04-11.
  • Fix : c'est rétrocompatible côté frontend (regex avec fallback). Mais à terme migrer le SYSTEM_PROMPT pour imposer le nouveau format.

Reranker retourne ~0 sur du contenu technique abstrait → enterre le bon chunk

  • Cause : le reranker bge-v2-m3 est peu confiant sur du jargon technique.
  • Fix : c'est précisément la motivation du blending position-aware (RAG Fusion v2). Cf. ADR-005. Si tu vois encore des cas, considérer ajuster les ratios (75/2585/15 sur top-3).

Frontend

display: flex dans une CSS scoped écrase le hidden lg:flex Tailwind

  • Cause : la spécificité CSS scoped batt utilities.
  • Fix : préférer Tailwind utilities partout. Si tu dois absolument scoped, utiliser !important ou @apply.

Card autocomplete @ ne matche pas un nom japonais / accentué

  • Cause : \b regex Unicode-incompatible (cf. backend ci-dessus, même piège).
  • Fix : useArbiterMarkdown.ts:74-81 — lookahead (?=\\s|$|[^\\p{L}\\p{N}_]) avec flag u.

CardZoomModal ne s'ouvre pas après reload

  • Cause : cardLookup n'a pas été reconstruit depuis les messages persistés en localStorage.
  • Fix : usePlaySession appelle rebuildFromMessages() on mount. Vérifier que ce path n'a pas été cassé.

SSE casse à 60s pile et UI affiche network error

  • Cause : NPM proxy_read_timeout 60s + heartbeat backend pas émis.
  • Fix : vérifier que setInterval heartbeat 8s est bien armé dans le service streamSSE. Pattern dans routes/ask.ts.

Infra

TEI répond 000 (curl no response)

  • Cause : port custom Unraid (8099 au lieu de 80, 8990 au lieu de 8090).
  • Fix : suspecter d'abord le port. Cf. mémoire reference_unraid_ports.md.

Container oracle SSH timeout

  • Cause : VM oracle down ou auth ed25519 cassée.
  • Fix :
    • ssh -i /app/ssh/id_ed25519 oracle@<host> "cd /home/oracle/work && claude -p" <<< "test"
    • Si timeout : SSH server down, restart la VM
    • Si Permission denied : vérifier authorized_keys côté VM, vérifier que la clé privée n'a pas été régénérée

Wrapper oracle rejette toutes les commandes

  • Cause : préfixe strict du wrapper modifié sans aligner les autres endroits.
  • Fix : 3 endroits doivent matcher (/home/oracle/bin/oracle-claude.sh PREFIX, CLAUDE_SSH_WORKDIR env, permissions.allow/additionalDirectories du settings.json oracle). Cf. securite/ssh-oracle.md.

Logs spam "EADDRINUSE :::3000"

  • Cause : container restart trop rapide, l'ancien process pas encore mort.
  • Fix : docker compose down && docker compose up -d (au lieu de restart).

BDD

Migration Drizzle qui ne s'applique pas

  • Cause : drizzle-kit generate n'a pas détecté le diff (rare). Ou la table __drizzle_migrations__ est désynchronisée.
  • Fix : vérifier le contenu de migrations/ vs src/schema.ts. Si nécessaire, npm run db:migrate manuel pour forcer.

database.db is locked

  • Cause : un autre process / container tient le fichier.
  • Fix : lsof /app/data/database.db (depuis Unraid CLI) pour identifier. Souvent un ancien container qui n'est pas vraiment mort.