Le mensonge de l'index

Voici la chronique de cette nuit blanche.


Le conteneur est vert. C'est la couleur du mensonge.

Docker prétend que tout va bien, Traefik fait le passe-plat avec zèle, le statut est "Healthy". Mais derrière l'interface propre et moderne de la v2, c'est le vide. Vingt-huit workflows. Vingt-huit automates qui tournaient en silence dans l'ancienne version v0.x, et qui, ce soir, n'existent plus.

J'ai migré. J'ai voulu moderniser. J'ai quitté le confort crasseux d'un vieux MySQL pour la rigueur d'un PostgreSQL 16. Le résultat ? Une base de données qui me regarde sans rien dire, et une liste de "Permissions perdus".


L'identité n'existe plus

J'ai commencé par la méthode brute. L'injection SQL à l'ancienne pour forcer les liens. J'ai voulu rattacher mes machines à mon userId, comme avant.

PostgreSQL m'a ri au nez :

ERROR: column "userId" of relation "shared_workflow" does not exist

Le monde a changé pendant que je dormais. On ne possède plus rien en nom propre dans n8n. L'individualisme du userId est mort, remplacé par la bureaucratie du projectId. J'ai dû fouiller la table project_relation comme on fouille les poubelles pour retrouver mon nouveau matricule. J'ai injecté l'ID. INSERT 0 0.

Rien. Le système s'en fout.


Le bruit blanc

Impossible de réfléchir. Les logs dégueulaient des erreurs en continu.

ValidationError: The 'X-Forwarded-For' header is set but the Express 'trust proxy' setting is false.

Le proxy mentait sur l'origine du monde. Traefik et n8n se renvoyaient la balle sur qui avait le droit de parler à qui. J'ai dû faire taire le bruit avec une variable d'environnement, N8N_PROXY_HOPS=2. Une ligne dans un YAML pour dire à l'application d'arrêter d'être paranoïaque. Le silence est revenu dans les logs.

Mais l'écran restait vide.


La terre brûlée

J'ai tenté de jouer au diplomate avec les rôles. J'ai essayé project:owner. Refusé. Il fallait être project:personalOwner. Une nuance sémantique qui te bloque l'accès à ta propre création.

User attempted to access a workflow without permissions

J'ai arrêté d'être subtil. J'ai sorti Python. J'ai écrit un script pour effacer la mémoire des fichiers JSON. J'ai strippé les versionId, supprimé les identités, généré des faux UUIDs. J'ai transformé mes workflows historiques en orphelins amnésiques pour forcer le système à les accepter comme des nouveaux nés.

L'import a fonctionné. Mais les droits sautaient encore.


Le paradoxe d'Alpine

C'est là que la folie s'installe. Le moment où la machine te ment droit dans les yeux. C'est le boss final.

Je fais un SELECT. La ligne est là. Je la vois.

Je fais un INSERT dans shared_workflow qui référence cette ligne exacte.

Et Postgres hurle :

Key (workflowId)=(svx...) is not present in table "workflow_entity".

Je regarde la ligne. Elle est là. La base me dit qu'elle n'est pas là. C'est un gaslighting numérique. Une dissonance cognitive codée en C.

La vérité était enfouie dans une mise à jour silencieuse de l'OS du conteneur. Une histoire de Collation. La méthode de tri d'Alpine Linux a changé. La base de données, créée sous une ancienne version, continuait de lire les index avec une carte qui ne correspondait plus au territoire.

Les données étaient là, mais l'index était aveugle. Il pointait vers le vide.


La rédemption par l'index

Pas de code. Pas de refonte. Juste deux commandes pour forcer la base à relire la réalité telle qu'elle est, et non telle qu'elle croit qu'elle est.

REINDEX TABLE "workflow_entity";
REINDEX TABLE "shared_workflow";

Le serveur a gratté quelques millisecondes. Et soudain : INSERT 0 28.

Les workflows sont apparus. Les voyants se sont allumés. Le flux a repris.


Tout fonctionne. La stack est propre, PostgreSQL 16.11 ronronne. Mais je garde en tête cet avertissement silencieux du début de soirée : database 'n8n' has no actual collation version.

Nous construisons des cathédrales de logique sur des fondations de sable mouvant. Il suffit qu'un mainteneur change l'ordre alphabétique dans une librairie système pour que votre réalité cesse d'exister.