Troubleshooting
Fix common WASH PRO CRM problems — Docker startup, login, MQTT connectivity, ports, DATA_DIR paths, and service health checks.
Updating Dynamic API Platform
In-app updater in panel :8080 is disabled in WASH. Use:
./scripts/update-dynamic-api.sh
docker compose up -d --build dynamic-api dynamic-api-panel
Current vendored version: v1.5.13.
CRM update failed or wrong paths
WASH uses update-bridge for in-Dashboard updates (not the Dynamic API panel updater).
- Open Dashboard → Settings → Integrity and repair (administrator).
- Click Check integrity — review paths (
WASH_HOST_PROJECT_ROOT,DATA_DIR), missing files, Docker socket, stuck jobs. - Select fixes and click Apply fixes (sync
.env, Mosquitto repair,init-seed, clear stuck job). - Rebuild if needed:
docker compose up -d --build update-bridge dashboard
Manual fallback:
./scripts/fix-mqtt.sh
docker compose run --rm init-seed
Ensure .env has correct WASH_HOST_PROJECT_ROOT (absolute host path to the project) and DATA_DIR — host data directory (./data, /var/lib/wash-pro-crm, /mnt/hdd/data, etc.).
False “suspicious DATA_DIR” warning (v1.1.19+)
Symptoms: Integrity and repair warns about DATA_DIR even though the path is valid (e.g. /mnt/hdd/data).
Cause (before v1.1.19): the check flagged any absolute DATA_DIR that did not match {project}/data.
Fix (v1.1.19+): external host paths are valid; warning only when DATA_DIR points inside the container /deploy mount. Upgrade and rebuild:
git pull
docker compose up -d --build update-bridge dashboard
Do not apply the “Set DATA_DIR=./data” fix if your data already lives on an external disk.
Updates not shown / reset on page load (v1.1.18+)
Symptoms: update banner disappears after F5; empty “latest version” on component cards; “GitHub API rate limit exceeded”.
Cause (before v1.1.18): without GITHUB_TOKEN, GitHub REST API allows 60 requests/hour per IP; Dashboard forced API checks on every load and every 3 s during updates.
Fix (v1.1.18+):
update-bridgefalls back togit ls-remotewhen API quota is exhausted — token not required for public repos- normal page load and job progress polling use cache; GitHub is queried only via Check now
- on API errors, last known versions are kept in
DATA_DIR/update-bridge/state.json
Upgrade to v1.1.18 and rebuild:
git pull
docker compose up -d --build update-bridge dashboard
GITHUB_TOKEN in .env is optional (release notes and 5000 req/h). Not needed for public installs.
Local server edits block git pull
Symptoms: Dashboard update “resets” immediately — progress vanishes in 1–2 s, history shows failed, step “Fetch from GitHub”.
Cause (before v1.1.20): git pull --ff-only aborts on any tracked file modifications (“local changes would be overwritten”). Localhost clones are often clean; production hosts after manual edits or scp are not.
Fix (v1.1.20+): updater runs git fetch + git reset --hard origin/main — resets tracked files only; preserves .env, docker-compose.override.yml, local/, DATA_DIR.
Recommended pattern:
cp docker-compose.override.yml.example docker-compose.override.yml
mkdir -p local
cp local/apply-server-patches.sh.example local/apply-server-patches.sh
chmod +x local/apply-server-patches.sh
git checkout -- docker-compose.yml
docker-compose.override.yml— untracked, loaded byscripts/start.shlocal/apply-server-patches.sh— run by updater aftergit pull
See Deployment, Configuration.
“text/html is not a valid JavaScript MIME type” (v1.1.29+)
Symptoms: Interface error or “Failed to load page” mentioning text/html and JavaScript MIME type; often after docker compose up -d --build dashboard or a CRM update from Dashboard.
Cause: the browser (often Safari) keeps a stale index.html pointing at removed JS bundles (/assets/index-….js). Before v1.1.29 nginx could return HTML instead of 404 — the browser tried to run HTML as JS.
Fix:
- Hard reload:
⌘⇧R(Mac) or close the tab and open CRM again. - Upgrade to v1.1.29+ and rebuild dashboard:
docker compose up -d --build dashboard. - Do not mix localhost:80 (Docker) and localhost:5173 (
npm run dev) in the same workflow. - For UI dev, use either
npm run devor Docker only.
Update fails at build: Docker Hub timeout (Mac / localhost)
Symptoms: CRM update in Dashboard reaches Build and fails; job log shows DeadlineExceeded, registry-1.docker.io, failed to resolve source metadata, or exit code 1. GitHub (source fetch) succeeds.
Cause: Docker on Mac cannot pull base images (node:20-alpine, nginx:alpine) from Docker Hub in time — network, VPN, Docker Desktop DNS, or registry blocking. This is not a CRM logic bug; on a server with normal Hub access (e.g. 192.168.1.151) the same release builds fine.
Diagnose on the host:
docker pull node:20-alpine
docker pull nginx:alpine
If these hang or fail with DeadlineExceeded, the issue is Docker Hub access, not WASH.
What to do:
- Check internet; disable or change VPN if it blocks
registry-1.docker.io. - Docker Desktop → Settings → Docker Engine — for DNS issues, temporarily add
"dns": ["8.8.8.8", "1.1.1.1"]and restart Docker. - After successful
docker pull, retry update from Dashboard (Settings → Software updates). - For UI dev without full rebuild:
cd dashboard && npm run dev(port 5173). - Manual build on host (when pull works):
cd /path/to/WASH-PRO-CRM
git fetch origin && git checkout v1.1.66
docker compose up -d --build dashboard update-bridge
v1.1.25: update-bridge shows a clear message instead of raw log tail on Hub timeout.
Stuck update spinner (v1.1.50+)
Symptoms: header or Settings → Software updates shows a spinning indicator forever; job status stays queued though the target version is already installed.
Cause: stale queued job in DATA_DIR/update-bridge/state.json from an interrupted update.
Fix:
- Upgrade to v1.1.50+ (auto-reconciles stale jobs when target version matches).
- Settings → Integrity and repair → Apply fixes — includes
clear_stuck_job, or API:
curl -X POST http://localhost/api/crm/updates/repair \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"actions":["clear_stuck_job"]}'
- If needed:
docker compose restart update-bridge
v1.1.51+: starting a new update reconciles stale active jobs automatically.
Post page slow or hanging (v1.1.48+)
Large telemetry volume (hundreds of thousands of rows per post) can slow the post detail page if an old Dashboard version loads all CRM telemetry client-side.
Fix: upgrade to v1.1.48+ (MongoDB indexes) and v1.1.51+ (post history: server filter, 100 rows, Load more above table, count=false). Use Archive to purge old telemetry if retention policy allows.
“/deploy is not a git repository” in integrity (v1.1.21+)
Symptoms: warning “/deploy is not a git repository” or “Git in /deploy unavailable” despite git clone install.
Cause: Git 2.35+ dubious ownership — host .git owned by a different user than update-bridge in the container (root). The repo exists; the check was wrong.
Fix (v1.1.21+): update-bridge registers safe.directory /deploy on startup; integrity check does the same. Or manually:
docker exec wash-update-bridge git config --global --add safe.directory /deploy
Without .git on the host (file copy without clone) — Dashboard auto-update will not work; use git clone or manual updates.
init-seed: Exited status
Exited (0) is normal (one-time container).
On error:
docker logs wash-init-seed
./scripts/run-init-seed.sh
Migration from RabbitMQ to MQTT
If you previously used RabbitMQ (AMQP, port 5672):
./scripts/migrate-to-mqtt.sh
docker compose up -d --build message-processor
In .env replace RABBITMQ_* with MQTT_*. Controllers must publish to topic wash/telemetry/{type} (QoS 1), not AMQP exchange.
Details: MQTT.
MQTT
User / password issues
./scripts/fix-mqtt.sh
docker compose up -d --build message-processor
Script refreshes Mosquitto conf; an existing passwd is not overwritten from .env (so post sync is not wiped). Post accounts — via "Sync MQTT" or processor startup. Force-reset system from .env: FORCE_MQTT_SYSTEM_PASS=1 ./scripts/fix-mqtt.sh.
Post cannot connect / "not authorised"
- Panel login/password =
settings.mqttLogin/settings.mqttPasswordfrom CRM (notsystem). - Publish topic:
washpro/{serial}/state/..., where{serial}=posts.serialNumber. - After MQTT data change in CRM — MQTT sync.
./scripts/fix-mqtt.sh— ifsystemfor CRM is broken.- (before v1.1.54) saving the post name on the post detail page could wipe MQTT credentials from
posts.settings; after restart/sync-usersMosquitto kept onlysystem. Upgrade to v1.1.54+, restore login/password on the post card, then sync MQTT again.
ACL / foreign serial in topic
Post cannot publish to topic with another serial — Mosquitto will reject. If CRM receives message with mismatched payload — only serial from topic is used.
Full MQTT reset (data in DATA_DIR, not Docker volume):
docker compose stop mosquitto mosquitto-init
rm -rf "${DATA_DIR:-./data}/mosquitto/data"/* "${DATA_DIR:-./data}/mosquitto/config"/*
./scripts/start.sh
Connection check:
docker exec wash-mosquitto mosquitto_sub -h 127.0.0.1 -p 1884 -t '$SYS/broker/version' -C 1 -W 3
Users page is empty
- Ensure you are Administrator (
manage_usersorview_logs) - Check API:
curl -H "Authorization: Bearer TOKEN" http://localhost:3001/api/users?page=1&limit=5 - Update Dashboard:
docker compose up -d --build dashboard - Re-login (expired JWT)
Telegram: "No news" / "News (N)" without text
- Dashboard → Publications — status Published (not "Draft")
- Hide after field — leave empty or date after publication
- Rebuild and restart information bot:
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d --build pyorch-bridge
# Dashboard → Telegram → ▶ on information bot
- In Telegram:
/startin private chat (not group), then 📰 News - Image URL — direct jpg/png link, up to 10 MB, accessible from internet
Telegram: no automatic news broadcast
- User must send
/startto bot in private chat (subscriber registration) - News — status Published; publication date set automatically
- Wait up to 30 s after publish
- News created before user's first
/startarrive only via 📰 News button, not push broadcast
Dashboard: gray screen when navigating sections
Since v1.1.12 JS chunk retry and RouteErrorBoundary added. If screen is blank:
- Refresh page (F5)
- Rebuild dashboard:
docker compose up -d --build dashboard - Clear browser cache for
localhost
Telegram: bot responds in group / others' messages visible
Since v1.1.11 bots work only in private chats. Open bot via QR or t.me/... link → /start. In groups bot does not respond.
Telegram: "Unauthorized" when creating bot
PYORCHESTRATOR_ENABLED=truein.envand./scripts/start.sh- Health:
curl http://localhost/api/telegram-bots/health - Rebuild:
docker compose … up -d --build dashboard pyorch-bridge - Refresh page / re-login
- Logs:
docker logs wash-pyorch-bridge --tail 50
Telegram: "PyOrchestrator unavailable"
docker compose ps | grep pyorch
docker logs wash-pyorch-backend
curl -s http://localhost:8000/health
Bridge credentials: PYORCH_DASHBOARD_EMAIL / PYORCH_DASHBOARD_PASSWORD.
Telegram bot silent / runtime: redis ConnectionError
After rebuilding pyorch-redis or pyorch-backend, runtime may keep old Redis connection.
chmod +x ./scripts/fix-pyorch.sh
./scripts/fix-pyorch.sh
Or manually:
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml restart pyorch-runtime pyorch-scheduler pyorch-bridge
Then Dashboard → Telegram — Stop → Start on bot.
Telegram: duplicate replies (old + new format)
Cause — two polling processes on one token (old PyOrchestrator demo script + new bridge template).
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d --build pyorch-bridge
# via API or Dashboard: POST /api/telegram-bots/bots/refresh
Bridge stops legacy bots and applies token lock. Bot reply footer should show Шаблон бота v2.7.
Telegram: "Private bot" for staff
- Dashboard → Users — set Telegram user_id (number from @userinfobot)
- User must be active, with assigned group (Viewer / Operator / Administrator)
- Restart bot or wait for session cache refresh (up to 5 min)
Telegram: Viewer cannot create site
Expected RBAC behavior — Viewer group has only view. For creating washes and post commands assign Operator or Administrator.
Bot silent, run logs: Temporary failure in name resolution: sandbox runtime was only on wash-internal network (no internet) and could not reach api.telegram.org. After updating docker-compose.pyorchestrator.yml recreate runtime:
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d --build pyorch-runtime pyorch-backend pyorch-bridge
Bot delete fails with 500: PyOrchestrator had notifications referencing run. Fixed in delete_script_record — rebuild pyorch-backend.
docker exec wash-pyorch-runtime python -c "import urllib.request; urllib.request.urlopen('https://api.telegram.org', timeout=10); print('telegram ok')"
docker logs wash-pyorch-runtime --tail 30
PyOrchestrator MCP: "unreachable" / does not start
In WASH the service is named pyorch-mcp, while backend defaults to http://mcp:8010. Overlay sets MCP_INTERNAL_URL and network alias mcp.
docker compose -f docker-compose.yml -f docker-compose.pyorchestrator.yml up -d pyorch-mcp pyorch-backend
docker logs wash-pyorch-mcp --tail 30
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8010/mcp # 200/405/406 — normal
Check from API (admin JWT required):
curl -s http://localhost:8000/api/v1/mcp/info -H "Authorization: Bearer TOKEN" | jq .status
# expected: "ok"
Resources: PyOrchestrator "Stopped"
Indicator checks /api/telegram-bots/health. If PyOrch is off — expected. Dynamic API checked via /api/health.
Post status "Offline" with working panel
Post is online if lastMessageAt in /api/crm/post-states is not older than 30 seconds. Check:
- Telemetry arrives on topic
washpro/{serial}/state/process(or other suffix). docker logs wash-message-processor— processing errors.- Serial in topic =
serialNumberin CRM.
ETH “MQTT OK”, CRM “Offline” (v1.1.57+)
Often not the post password — a mismatch of the CRM system password:
- ETH authenticates with its own
mqttLogin/mqttPasswordand publishes telemetry. - CRM (
message-processor) connects assystem. If Settings → MQTT still has the seed passwordwashprowhile.env/ Mosquitto use anotherMQTT_PASSWORD, the processor getsNot authorizedand never refresheslastMessageAt.
From v1.1.57: on startup the processor heals seed/washpro to MQTT_PASSWORD and syncs the passwd before connecting; mosquitto-init no longer overwrites an existing passwd from .env on every restart.
Check:
docker logs wash-message-processor --tail 50 | grep -E 'Connected|Not authorized|Healed|passwd synced'
./scripts/fix-mqtt.sh
docker compose up -d --build message-processor
Telemetry not updating
- Serial in topic (
{dt_pref}/{serial}/state/...) orpostSerialin legacy JSON = postserialNumberin CRM docker logs wash-message-processor- DLQ
wash/dlq - MQTT log: Dashboard → Logs or
/api/crm/telemetry
Commands and prices not reaching post
- MQTT prefix in CRM (
dt_pref) matches panel setting (get_settings.remote) docker logs wash-message-processor— publish errors- Check from server:
mosquitto_pub -h localhost -p 1883 -u system -P 'PASSWORD' -q 1 \ -t 'washpro/SERIAL/set/command' -m '{"cmd":1}' - HTTP API:
curl http://localhost/api/crm/post-device/posts/SERIAL/commandwith JWT (see MQTT) - Rebuild after update:
docker compose up -d --build message-processor dashboard
CORS
Add origin to CORS_ORIGIN, restart dynamic-api.
Dashboard won't open
docker compose ps
docker logs wash-dashboard
Backup
docker logs wash-backup
Manual run — Dashboard → Backups.
Full restart
docker compose down
docker compose up -d --build
MongoDB and other service data in DATA_DIR (default ./data), see data/README.md.
Help
docker compose logs > logs.txt- GitHub issue with
APP_VERSION,docker compose ps, reproduction steps