Incident: W3 File Upload Broken — 2026-07-01

PoleWartość
IDINCIDENT-2026-07-01-001
PlatformaW3 (pinbox24.com/w3)
SevernośćP1 — upload plików niedostępny, import Excel zablokowany
StatusRESOLVED
Wykryto2026-07-01T10:20Z (po sesji nocnej)
Root cause ustalony2026-07-01T11:45Z
Hotfix wdrożony2026-07-01T11:58Z
Zweryfikowano2026-07-01T12:37Z
GH Issueradieu/p24-infra#2402 (CLOSED)

Symptom

Po nocy użytkownik zgłosił niemożność załączenia pliku w W3. Każda próba uploadu kończyła się błędem w przeglądarce. Import Excel (działający od poprzedniej sesji) nie mógł być przetestowany.

Nginx zwracał HTTP 400 od v32-prod do przeglądarki. v32-prod odbierał 400 od s3-v32-prod.


Oś czasu

Czas (UTC)Zdarzenie
2026-07-01 00:14Incident #2350 — rotacja mongodb_rs0_admin_password, force-recreate v32-prod + s3-v32-prod
10:20Użytkownik zgłasza zepsute uploady
10:45Potwierdzono: nginx → v32-prod → s3-v32-prod zwraca 400
10:50Wasabi upload działa — plik w Wasabi ale metadata nie trafia do w3_db
11:30Zidentyfikowano błąd: fileToSave.save() w s3-v32-prod — Mongoose 4.x/mongodb 2.x vs MongoDB 6.x
11:45Root cause: Unsupported OP_QUERY command: insert — OP_INSERT usunięty w MongoDB 5.1+
11:55Użytkownik zatwierdza hotfix (“tak”)
11:58Hotfix wdrożony, PM2 restart — oba workery online
12:03Pierwszy upload po hotfixie — [s3-upload] MongoDB save failed (file in Wasabi, returning success) — fallback działa
12:37Weryfikacja użytkownika: upload OK, [uploadFilev2] w3_db mirror insert OK, _id: 6a450a00aea41e00116a8f0a

Root cause

Bezpośrednia przyczyna

Incident #2350 (rotacja hasła mongodb_rs0_admin_password, ~00:14 UTC) wymusił force-recreate kontenerów v32-prod i s3-v32-prod. Po restarcie s3-v32-prod nie mógł zapisać metadanych pliku do MongoDB.

Głębsza przyczyna

s3-v32-prod używa Mongoose 4.x z mongodb driver 2.x — legacy driver używający protokołu wire OP_INSERT / OP_QUERY.

MongoDB 6.x (bms-2/bms-3 rs0) nie obsługuje tych opcodes — usunięte od wersji 5.1. Każda próba fileToSave.save() kończyła się:

Unsupported OP_QUERY command: insert. The client driver may require an upgrade.
For more details see https://dochub.mongodb.org/core/legacy-opcode-removal

Kod obsługi błędu: res.status(400).json(err) — zwracał 400 do v32-prod, który nie wyzwalał FIX-2026-06-30 mirror (sprawdza body.result[0]).

Dlaczego wcześniej działało

Przed incident #2350, s3-v32-prod łączył się z artnet (MongoDB 4.4 lub wcześniejszy), który obsługiwał OP_INSERT. Po migracji DB_URI na bms-2/rs0 (MongoDB 6.x) podczas cleanup po #2350, stary driver przestał działać.


Zmienione pliki / kontenery

KontenerPlikZmianaBackup
s3-v32-prod na bms-1/app/build/src/api/storage/controller.jsRejection handler .save(): res.status(400).json(err) → log + res.json(props.buildSuccess([object]))/tmp/s3-controller-fix.js (kopia przed patchem)

Dokładna zmiana

// PRZED:
        }, (err) => {
            res.status(400).json(err);
        });
 
// PO:
        }, (err) => {
            console.error('[s3-upload] MongoDB save failed (file in Wasabi, returning success):', err && err.message);
            if (index === indexLength) { filesAdded.push(object); index += 1; res.json(props.buildSuccess(filesAdded)); } else { filesAdded.push(object); index += 1; }
        });

Weryfikacja fix

s3-v32-prod PM2 err log 12:03 UTC:
[s3-upload] MongoDB save failed (file in Wasabi, returning success): Unsupported OP_QUERY command: insert.

v32-prod PM2 out log 12:37 UTC:
POST /api/files/590c6d334704d811efc9fd5a/upload 200 849 - 157ms
[uploadFilev2] w3_db mirror insert OK, _id: 6a450a00aea41e00116a8f0a

nginx log 12:37 UTC:
GET /api/files/.../list 200 948 — file visible in list ✅

Długoterminowy fix

Upgrade Mongoose + driver w s3-v32-prod: Mongoose 4.x → 6.x, mongodb driver 2.x → 4.x.

Uwaga: s3-v32-prod jest skompilowanym TypeScript w kontenerze — zmiana wymaga rebuild image i deployu. Niski priorytet (hotfix fallback jest stabilny), ale powinien być zrobiony przed kolejną migracją.

Issue: brak osobnego issue — wrzucić w backlog upgradu bms-1 containers (#745).


Rollback

Jeśli hotfix powoduje problemy:

# Na bms-1:
# Kopia pliku przed patchem jest w /tmp/s3-controller-fix.js (oryginał)
# Ale UWAGA: /tmp/s3-controller-fix.js jest już po patchu — backup jest w git
# Rollback: rebuild s3-v32-prod image lub force-recreate z image c4167e55cda0
 
# Szybki rollback (PM2 reload z poprzednią wersją):
# Nie ma prostego rollbacku bez backup pliku — hotfix jest tylko w pamięci kontenera
# Po restart kontenera (docker restart s3-v32-prod) hotfix NIE przetrwa

WAŻNE: Hotfix jest in-memory — nie przetrwa docker restart s3-v32-prod (tylko PM2 restart wewnątrz kontenera). Przy następnym pełnym recreate kontenera hotfix zniknie. Patrz #2403 i #2402 — na liście do trwałego fixa w image.


Lekcje

  1. Stary driver Mongoose — s3-v32-prod ma legacy driver niekompatybilny z MongoDB 6.x. Zanim zmienia się DB_URI, trzeba sprawdzić wersję drivera w kontenerze.
  2. PM2 log credential exposure — s3-v32-prod i v42-prod logują pełny URI połączenia MongoDB przy starcie. To był root cause incident #2350 i wraca po każdym restarcie. Fix w issue #2397.
  3. FIX-2026-06-30 mirror — działa jako skuteczny backstop: nawet jeśli s3-v32-prod nie może zapisać do MongoDB, v32-prod zapisuje do w3_db. Ta redundancja uratowała upload.
  4. Monitoring gap — brak alertu na HTTP 400 z wewnętrznych serwisów (s3-v32-prod → v32-prod). Dodać probe na endpoint /api/files/.../upload lub log monitor.