Troubleshooting
Procédures de résolution des problèmes connus
Troubleshooting — procédures de résolution
Wiki.js — écritures via GraphQL refusées
Wiki.js — page affiche une erreur 500 après modification directe en base
Profil Hermes — modèle Ollama Cloud rejeté (erreur 404)
Gateway Slack — Slack app token already in use
n8n — webhooks non enregistrés après réimport
n8n — reset impossible avec n8nio/n8n:latest
n8n — hash de mot de passe rejeté
SilverBullet — échecs répétés d'authentification
Mots de passe contenant $ — interpolation shell
Backups — choix entre cloud et local
Kanban MyMoment — colonnes obsolètes
SSH — clé privée perdue, impossible de se connecter au VPS
Restaurer le VPS depuis un backup complet
Hermes WebUI / Open WebUI — Server Connection Error / TransferEncodingError: 400, message='Not enough data to satisfy transfer length header.'
Open WebUI — configuration Ollama Cloud
Open WebUI — pas de modèles Hermes (OpenAI-compatible)
Services systemd créés
Hermes — profil CEO consomme trop de tokens (Kimi 2.7)
Cette page centralise les problèmes déjà rencontrés sur le VPS et leurs solutions. Un agent qui rencontre un bug connu doit d'abord consulter cette page avant d'inventer une nouvelle procédure.
Symptôme : un token JWT admin valide permet de lire mais les mutations pages { create } / update retournent une erreur de permission.
Cause : le compte admin créé lors du setup n'a pas le rôle système write:pages.
Solution : modifier le contenu directement via l'interface web (éditeur Markdown), ou mettre à jour le rôle système de l'utilisateur dans l'administration Wiki.js.
Symptôme : la page est accessible en édition mais retourne 500 une fois publiée.
Cause : le champ render est vide ou corrompu après une mise à jour SQL.
Solution :
1. Récupérer le contenu Markdown depuis la table pages.
2. Générer le rendu HTML avec une bibliothèque Markdown (ex: Python markdown).
3. Réinjecter le HTML dans le champ render.
4. Reconstruire la table pageTree à partir des titres (# → ######).
5. Redémarrer le container wiki-js.
Symptôme : hermes chat --profile <profil> échoue avec model not found.
Cause : le modèle configuré est un alias invalide (ex: kimi2.7-code:32b).
Solution : utiliser le modèle valide kimi-k2.7-code pour le provider ollama-cloud.
Slack app token already in useSymptôme : le gateway refuse de démarrer en indiquant qu'un autre processus utilise le même token.
Cause : un autre gateway est déjà connecté avec le même SLACK_APP_TOKEN.
Solution : arrêter l'ancien processus hermes gateway run, puis relancer le nouveau.
Symptôme : un workflow importé et activé via CLI ne déclenche pas les webhooks.
Cause : n8n update:workflow --active=true + restart ne suffit pas à enregistrer les webhooks.
Solution : appeler l'API REST PATCH /rest/workflows/{id} avec active=true pendant que n8n tourne, ou activer/désactiver le workflow dans l'éditeur web.
n8nio/n8n:latestSymptôme : réinstallation de n8n avec l'image latest échoue sur Could not find any entity of type Project.
Cause : l'image latest a un schéma de base de données différent de la version qui a créé la DB.
Solution : utiliser l'image Docker exacte qui a créé la base (ex: n8nio/n8n:1.87.0).
Symptôme : mot de passe injecté en base n8n non reconnu au login.
Cause : n8n attend un hash bcrypt format $2a$, pas $2b$.
Solution : générer le hash avec bcrypt en spécifiant le prefix $2a$.
Symptôme : impossible de se connecter à SilverBullet malgré un mot de passe correct.
Cause : problème de hash/password/env non documenté.
Solution : SilverBullet a été abandonné au profit de Wiki.js. Ne pas réinstaller SilverBullet.
$ — interpolation shellSymptôme : commandes avec des mots de passe échouent ou injectent des variables vides.
Cause : le caractère $ est interprété par le shell.
Solution : passer les mots de passe via des variables d'environnement ou des fichiers, jamais inline sans quoting.
Préférence utilisateur : privilégier les backups locaux sur le VPS lorsque l'auth cloud ou les quotas posent problème.
Rappel : les anciennes colonnes backlog, tournage, post-production, validation, livré ont été remplacées par le workflow générique à-faire → en-cours → bloqué → terminé.
Symptôme : http://135.125.226.248:8888/files ne répond pas, ou les identifiants admin sont rejetés.
Causes :
filebrowser est arrêté.database.db dans /home/ubuntu/filebrowser-config/ est corrompue.Solution — conteneur arrêté :
1. Vérifier l'état du conteneur :
bash docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep filebrowser
2. Le relancer :
bash docker start filebrowser
Solution — base corrompue / mot de passe perdu :
1. Arrêter le conteneur :
bash docker stop filebrowser
2. Sauvegarder puis renommer la base corrompue :
bash mv /home/ubuntu/filebrowser-config/database.db /home/ubuntu/filebrowser-config/database.db.corrupted.$(date +%Y%m%d_%H%M%S)
3. Initialiser une nouvelle base et créer un admin :
bash P=$(openssl rand -base64 18) docker run --rm -v /home/ubuntu/filebrowser-config:/config -v /home/ubuntu/uploads:/srv filebrowser/filebrowser:latest users add yann "$P" --perm.admin --config /config/settings.json echo "$P" > /home/ubuntu/.filebrowser_admin_pwd.txt chmod 600 /home/ubuntu/.filebrowser_admin_pwd.txt
4. Relancer le conteneur :
bash docker start filebrowser
Prévention : activer le redémarrage automatique du conteneur :
bash docker update --restart unless-stopped filebrowser
Note : filebrowser expose le port 80 à l'intérieur du conteneur. Le port 8888 est mappé côté hôte par le lancement Docker. Si un nouveau conteneur est créé, il faut inclure le mapping -p 8888:80.
Symptôme : besoin de restaurer un outil, des configs ou l'ensemble du VPS.
Solution :
1. Identifier l'archive dans /home/ubuntu/vps-backups/ : ls -lt /home/ubuntu/vps-backups/.
2. Extraire dans un dossier temporaire :
mkdir -p /tmp/restore && tar xzf /home/ubuntu/vps-backups/vps_full_YYYYMMDD_HHMMSS.tar.gz -C /tmp/restore
3. Copier uniquement ce qu'il faut restaurer :
- configs applicatives : dossier dans /opt/<outil>
- Docker volumes : fichier .tar.gz dans docker-volumes/
- configs système : system/crontab.txt, system/systemd-user/
4. Pour un volume Docker :
docker volume rm <vol> && docker volume create <vol> docker run --rm -v <vol>:/data -v /tmp/restore/snapshot_*/docker-volumes:/backup alpine sh -c "cd /data && tar xzf /backup/<vol>.tar.gz"
5. Redémarrer les containers concernés : cd /opt/<outil> && docker compose restart.
Précaution : ne jamais restaurer par-dessus des données en production sans confirmer avec l'utilisateur.
Server Connection Error / TransferEncodingError: 400, message='Not enough data to satisfy transfer length header.'Symptôme : Open WebUI affiche Server Connection Error ou un message de payload tronqué TransferEncodingError: 400, message='Not enough data to satisfy transfer length header.'.
Cause : le gateway Hermes qui expose l'API compatible OpenAI (http://127.0.0.1:8642) n'est pas démarré, a planté, ou a été tué par un conflit avec un autre profil gateway.
Solution :
1. Vérifier que le serveur API Hermes répond sur le port 8642 :
bash curl -fsS http://127.0.0.1:8642/health
2. S'il ne répond pas, arrêter les anciens gateways et Open WebUI, puis redémarrer proprement :
bash sudo systemctl stop open-webui-hermes.service hermes-openwebui-gateway.service pkill -9 -f 'open-webui serve' pkill -9 -f 'hermes_cli.main gateway' sleep 3 sudo systemctl start hermes-openwebui-gateway.service sleep 5 curl -fsS http://127.0.0.1:8642/health sudo systemctl start open-webui-hermes.service
3. S'il y a un conflit double gateway, vérifier les services systemd et utiliser le wrapper avec --replace.
Symptôme : aucun modèle Ollama n'apparaît dans le sélecteur de modèles d'Open WebUI.
Cause : l'URL de l'API Ollama configurée dans Admin → Settings → Connections n'est pas un endpoint API valide (ex: https://ollama.com/settings/keys au lieu de https://ollama.com/api).
Solution :
1. Se connecter à https://openwebui.yann-ai.fr/admin/settings/connections
2. Configurer une connexion Ollama API avec :
- API Base URL : https://ollama.com/api
- API Key : la clé Ollama Cloud
3. Supprimer les connexions Ollama dupliquées.
4. Vérifier côté serveur :
bash curl -fsS https://ollama.com/api/tags
Symptôme : la liste de modèles ne contient que les modèles Ollama, pas ceux exposés par Hermes.
Cause : l'appel /v1/models sur l'API Hermes retourne 401 si la clé API_SERVER_KEY n'est pas fournie dans l'en-tête Authorization.
Solution : vérifier que le launcher Open WebUI contient la bonne OPENAI_API_KEY pointant vers API_SERVER_KEY.
Deux services systemd ont été créés pour rendre Open WebUI résilient :
hermes-openwebui-gateway.service — gateway Hermes avec l'API serveur sur 127.0.0.1:8642.open-webui-hermes.service — Open WebUI, dépendant du gateway.Commandes utiles :
sudo systemctl status hermes-openwebui-gateway.service open-webui-hermes.service
sudo systemctl restart hermes-openwebui-gateway.service
sudo systemctl restart open-webui-hermes.service
Copy
Symptôme : les profils greenpulse_ceo, mymoment_ceo et cashpilote_ceo sous kimi-k2.7-code utilisent beaucoup de tokens par session.
Causes :
- mymoment_ceo avait agent.max_turns: 300 (3× les autres profils).
- Mémoire injectée à chaque session : memory_char_limit: 2200 + user_char_limit: 1375.
- Compression déclenchée tardivement (threshold: 0.5).
- SOUL.md forçait la lecture de 3 pages wiki au démarrage.
- mymoment_ceo avait une state.db de 35 Mo avec 28 sessions, dont certaines à plusieurs millions de tokens.
Optimisations appliquées :
1. agent.max_turns ramené à 90 pour mymoment_ceo.
2. memory_char_limit réduit à 800 et user_char_limit à 400 sur les 3 CEO.
3. compression.threshold passé à 0.3 et hygiene_hard_message_limit à 150.
4. SOUL.md allégé : seule Règles-Générales est lue au démarrage.
5. Skills restreints aux seuls skills métier nécessaires.
6. Purge des sessions mymoment_ceo de plus de 7 jours : 21 sessions et 3479 messages supprimés, DB réduite de 35 Mo à 26 Mo.
Commande de purge manuelle si besoin :
python3 <<'PY'
import sqlite3
from datetime import datetime, timedelta
DB = '/home/ubuntu/.hermes/profiles/mymoment_ceo/state.db'
cutoff = (datetime.now() - timedelta(days=7)).timestamp()
conn = sqlite3.connect(DB)
cur = conn.cursor()
cur.execute("SELECT id FROM sessions WHERE started_at < ?", (cutoff,))
ids = [r[0] for r in cur.fetchall()]
if ids:
placeholders = ','.join('?' * len(ids))
cur.execute(f"DELETE FROM messages WHERE session_id IN ({placeholders})", ids)
cur.execute(f"DELETE FROM sessions WHERE id IN ({placeholders})", ids)
conn.commit()
conn.close()
conn = sqlite3.connect(DB); conn.execute("VACUUM"); conn.close()
PY
Copy
Symptôme : plus aucun accès SSH au VPS, la clé privée (fichier sur l'ordinateur personnel) a été perdue. La connexion par mot de passe ne marche pas depuis un poste externe.
Cause : la clé privée SSH n'existe que sur l'ordinateur de la personne qui se connecte. Le serveur ne garde que la partie publique. Elle ne peut pas être « récupérée » depuis le serveur.
Solution : demander à l'agent Hermes installé sur le VPS de générer une nouvelle clé et de la remettre :
ssh-keygen -t ed25519 -C 'vps-yann-2026' -f /root/.ssh/yann-vps-2026)./home/ubuntu/.ssh/authorized_keys (à côté des clés existantes monvps-ovh et ha-tunnel).ssh -i /root/.ssh/yann-vps-2026 ubuntu@127.0.0.1 → doit répondre « CONNEXION_OK »./home/ubuntu/workspace/cle_ssh_vps_yann.txt).~/.ssh/id_ed25519 (Mac/Linux) ou C:\Users\<moi>\.ssh\id_ed25519 (Windows), puis chmod 600 (Mac/Linux).ssh -i ~/.ssh/id_ed25519 ubuntu@135.125.226.248.Prévention : conserver une copie de secours de la clé privée dans un coffre-fort numérique (gestionnaire de mots de passe). Ne pas supprimer les anciennes entrées authorized_keys qui marchent encore.
hermes updateSymptôme : après une mise à jour d'Hermes, les gateways se redémarrent en boucle toutes les ~30 secondes ; les journaux affichent en alternance Slack app token was held by gateway PID xxx — explicit --replace handoff completed puis Slack app token already in use. Le bot Slack devient indisponible par intermittence.
Cause : plusieurs services systemd de gateways chargent le même SLACK_APP_TOKEN (un seul Socket Mode autorisé par token). Avant v0.21, l'ancienne gateway écrasait silencieusement la nouvelle. Depuis v0.21, --replace est réciproque : chaque gateway vole le token à la précédente, qui le reprend à son tour en redémarrant — boucle sans fin.
Solution : ne laisser le token Slack que dans UN seul profil (celui du bot réel, ex. mymoment_ceo) :
grep -l '^SLACK_APP_TOKEN' /home/ubuntu/.hermes/profiles/*/.envminimal) : sauvegarder puis renommer les variables sed -i 's/^SLACK_/DISABLED_SLACK_/' /home/ubuntu/.hermes/profiles/minimal/.envsudo systemctl restart hermes-openwebui-gateway.servicesudo journalctl --since '5 min ago' | grep -E 'token was held|already in use' ne doit plus rien afficher, et le log du bot (/home/ubuntu/.hermes/profiles/mymoment_ceo/logs/gateway.log) doit montrer Socket Mode connected.Prévention : après chaque hermes update, vérifier qu'aucune nouvelle gateway n'a pris le token Slack (le fichier .env d'un profil non-Slack ne doit contenir aucune ligne SLACK_ active). Une gateway obsolète en erreur depuis des semaines peut cacher ce symptôme (ex. profile dev lancé manuellement, 8700+ tentatives de reconnexion avant d'être stoppée) — les zombies [hermes] <defunct> sont inoffensifs et disparaissent au reboot.
Symptôme : Firefox/Chrome affichent un avertissement de sécurité sur un site du VPS (ex. wol.yann-ai.fr). Le certificat servi est expiré ou contient une chaîne périmée. openssl s_client renvoie « certificate has expired ».
Cause : la boucle de renouvellement automatique de NPM (Renewing SSL certs expiring within 30 days, chaque heure) n'a rien renouvelé depuis des mois — les configs de renouvellement de certains certificats étaient en mode standalone (impossible : le port 80 est occupé par nginx) ou sans webroot_map. De plus, un certbot bloqué laisse un verrou orphelin (.certbot.lock) qui empêche toute nouvelle tentative (erreur « Another instance of Certbot is already running »).
Solution (à faire dans l'ordre) :
for d in /home/ubuntu/docker/nginx-proxy-manager/letsencrypt/live/*/; do echo "$(basename $d) | $(sudo openssl x509 -enddate -noout -in $d/cert.pem | cut -d= -f2)"; donedocker exec nginx-proxy-manager-npm-1 sh -c 'for p in /proc/[0-9]*/cmdline; do c=$(tr "\0" " " < $p); case "$c" in *certbot*) kill -9 $(basename $(dirname $p));; esac; done'
docker exec nginx-proxy-manager-npm-1 rm -f /var/lib/letsencrypt/.certbot.lock /etc/letsencrypt/.certbot.lock
renewal/<domaine>.conf contient authenticator = webroot + un bloc [[webroot_map]] avec domaine = /data/letsencrypt-acme-challenge (sinon certbot demande le webroot en mode interactif et échoue en non-interactif).location ^~ /.well-known/acme-challenge/ { root /data/letsencrypt-acme-challenge; } sur le port 80 (sinon Let's Encrypt ne peut pas valider).docker exec nginx-proxy-manager-npm-1 certbot renew --cert-name <domaine> --force-renewal --non-interactive --no-random-sleep-on-renewdocker exec nginx-proxy-manager-npm-1 nginx -s reloadPrévention : après chaque ajout de domaine via la méthode certbot-manuel, vérifier que le renewal conf est en webroot avec webroot_map. Le renouvellement auto de NPM reprendra dès que les configs sont correctes. Test de la chaîne : openssl s_client -connect <domaine>:443 -servername <domaine> | grep 'Verify return code' → doit afficher (ok).