On the lederera dev box, the nrt self-service identification flow fails with “error during photo processing” when either (1) the vuer_cv container is stopped, or (2) the hairpin-NAT /etc/hosts fix is missing from vuer_oss. Two independent root causes, same symptom. This is a recipe-oriented runbook — a future engineer hitting this should check both.
Dev box only — and the box has MOVED (2026-07-01)
Observed on the old on-prem box (
lederera/192.168.1.93,ssh Facekom), which is now decommissioned. The current dev host is thefk-devTailscale VM (command ssh ops@fk-dev.taild4189d.ts.net— see dev-build-host); the class of failure below still applies there. This is a dev-box networking + container-state gotcha, not a product bug. The flow itself is correct — there is no dev config flag that skips face-detection recognition, so a down/unreachable CV service hard-fails the flow.
Symptom
- Customer-facing UI during nrt self-service identification: “error during photo processing”.
vuer_osslogs (exact strings, searchable):Failed to ping CV server: 'cv-lederera.facekomdev.net'Error in ping CV server: 'RequestError: Error: read ECONNRESET'CV server is down: 'cv-lederera.facekomdev.net'CV process error Error: Recipe missing no CV Service!
- Thrown at
server/cv/CVRecipe.js:88— the recipe is constructed without acvServicebecause the CV health-check already marked the host down.
Why the flow can’t skip it
The throw propagates up:
SelfServiceV2Service.photoCandidate (SelfServiceV2Service.js:1043, calls submitTaskRecognition unconditionally)
-> FlowService.submitTaskRecognition
-> RecognitionService.runRecognitions
-> CVRecipe (server/cv/CVRecipe.js:88) throws "Recipe missing no CV Service!"
For Agents
SelfServiceV2Service.js:1043callssubmitTaskRecognitionunconditionally — there is NO dev config flag that skips face-detection recognition.selfService.ui.disabledChecksonly covers girinfo / emrtd / kau — not face detection. So if CV is unreachable, the whole nrt photo step hard-fails. Fixing reachability is the only path; you cannot config your way around it on the dev box.
Root cause 1 — vuer_cv container stopped
The CV (computer-vision / face-recognition) service runs in its own container vuer_cv (image harbor.techteamer.com/facekom-devel/vuer_cv:4.6.2.DEV-...). On this box it was stopped:
docker ps -a
# vuer_cv Exited (255) 2 months ago
With it down, nginx returns 502 Bad Gateway for https://cv-lederera.facekomdev.net. Confirm via loopback (bypasses hairpin, hits the box’s own nginx):
curl -k --resolve cv-lederera.facekomdev.net:443:127.0.0.1 https://cv-lederera.facekomdev.net/
# 502 Bad Gateway -> upstream (vuer_cv) is downFix
docker start vuer_cvIt boots cleanly under supervisord (nginx, redis, the CV process, ~10 worker procs) and becomes Up (healthy) after ~2 min. After it’s up, the same loopback curl returns 404 on / (real upstream answering) instead of 502:
curl -k --resolve cv-lederera.facekomdev.net:443:127.0.0.1 https://cv-lederera.facekomdev.net/
# 404 -> upstream is alive (404 on bare / is expected, the real app is responding)Root cause 2 — hairpin NAT (host-network container → box’s own public IP)
vuer_oss runs with host networking. Its container /etc/hosts maps all *-lederera.facekomdev.net names (css / oss / api / cv / esign-* / library / lederera.test) to the box’s own LAN IP 192.168.1.93. A host-network container connecting to the box’s own public/LAN IP resets at the TLS handshake (“Connection reset by peer” right after Client Hello) — classic hairpin-NAT failure.
This is why CV ping fails with read ECONNRESET even when vuer_cv is up: the connection never completes the handshake.
Fix
Point those names at 127.0.0.1 instead of 192.168.1.93 inside vuer_oss’s /etc/hosts. Loopback reaches the same nginx with no hairpin:
docker exec vuer_oss sh -c "sed 's/192\.168\.1\.93/127.0.0.1/g' /etc/hosts > /tmp/hosts.new && cat /tmp/hosts.new > /etc/hosts"After this, vuer_oss logs:
CV server is available: 'cv-lederera.facekomdev.net'
and the CV ping recovers.
Use truncate+write, NOT
sed -i
/etc/hostsis a single-file bind mount. An in-place rewrite must truncate+write the same inode (... > /etc/hosts, orbase64 -d > /etc/hosts).sed -ifails withDevice or resource busybecause it tries to rename a temp file over the bind-mounted path.
CRITICAL caveat — the fix does not survive a restart
Re-apply after EVERY
vuer_ossrestart
vuer_oss’s/etc/hostsis regenerated by Docker on every container start (it’s a bind-mounted file Docker owns). So the hairpin edit DOES NOT survivedocker restart vuer_oss. Any restart re-breaks:
- CV reachability (re-triggers “error during photo processing”), and
- the
oss-ledereraexternal-API path used by instacash-cli.Re-apply the
/etc/hostsedit after anyvuer_ossrestart.
Also affects: bin/instacash-cli
The same hairpin reset previously broke bin/instacash-cli calls to oss-lederera.facekomdev.net/external/... (TLS reset, host-network container → own LAN IP). Same fix: map oss-lederera → 127.0.0.1 in vuer_oss’s /etc/hosts. (The single sed replace above already covers all *-lederera names, including oss-lederera.)
Quick recipe
Hitting "error during photo processing" or "CV server is down"?
- Is
vuer_cvrunning?docker ps -a | grep vuer_cv— ifExited,docker start vuer_cvand wait ~2 min forUp (healthy). Verify: loopback curl returns404not502.- Is the hairpin
/etc/hostsfix in place invuer_oss? Especially after anyvuer_ossrestart (the edit is wiped on every container start). Re-map*-lederera.facekomdev.net→127.0.0.1via truncate+write (neversed -i). Confirm viaCV server is availablein the logs.
Related
- vuer_cv — the CV / face-recognition service that must be
Up (healthy) - vuer_oss — host-network container whose
/etc/hostscarries the hairpin fix (CVRecipe.js:88,SelfServiceV2Service.js:1043) - infrastructure — dev-box networking, host-networking model, nginx subdomain routing
- vuer_docker — container orchestration /
docker startoperations - sms-verification-code-dev-testing — sibling dev-box gotcha discovered in the same nrt self-service testing session