Troubleshooting

A pragmatic fix-guide for the most common problems. For each symptom: brief explanation → diagnostics → fix.

General: reading logs

journalctl -u dvb-warppool -f --since "5 min ago"

For Docker:

docker logs -f dvb-warppool --since 5m

Temporarily raise the log level:

RUST_LOG=warppool=debug,info dvb-warppool-daemon

Targeted per crate:

RUST_LOG=warppool_stratum_v1=trace,warppool_bitcoin_rpc=debug,info dvb-warppool-daemon

RPC

getblockchaininfo failed: HTTP 401 — credentials rejected

Cookie or user/pass mismatch.

Diagnosis:

# Cookie auth:
cat ~/.bitcoin/.cookie       # should be "user:hexhash"
# user/pass auth:
grep -E "^rpc(user|password)" ~/.bitcoin/bitcoin.conf

Fix:

  • Cookie mode: make sure node.rpc_cookie_path in config.toml points to the correct file. Bitcoin Core has its own cookie files for regtest/testnet (~/.bitcoin/regtest/.cookie, ~/.bitcoin/testnet3/.cookie). The setup wizard typically shows the right path.
  • user/pass mode: in secrets.toml, rpc_user + rpc_pass must match the values in bitcoin.conf. In secrets.toml, not config.toml — otherwise the daemon complains at startup.
  • On permission errors: bitcoind runs as a different user; the cookie is 0600 and unreadable for your warppool user. The setup wizard catches this and suggests chmod g+r + group-add.

getblocktemplate failed: -8 ...

Bitcoin Core is reachable, but says no to the template.

Possible causes:

  • IBD running: warppool_rpc_ibd == 1. Wait until sync completes.
  • Wallet locked: getblocktemplate without -walletbroadcast=0 needs an unlocked wallet in Core. Unusual in a pool context, though — we use GBT without a wallet.
  • Too few peers: getpeerinfo shows 0 or 1. Core then refuses to mine to avoid ending up on a minority fork. Fix: wait, or use -minimumchainwork=0 for tests.

RPC latency high (Prometheus shows p99 > 1s)

Diagnosis:

  • Are many RPCs running in parallel? The daemon normally does ~1-5/s in steady state. If p99 is high: is Bitcoin Core on a slow disk or swapping?
  • tx-index=1 setup on HDD: makes GBT slow. SSD recommended.
  • Pruned node + old block request: doesn't happen on the normal pool path, but backup/restore workflows can trigger it.

Fix: usually a disk bottleneck. iotop / iostat shows this quickly.

ZMQ

Daemon only uses poll-loop, no ZMQ

Log line at startup:

zmq watcher: WARPPOOL_ZMQ_HASHBLOCK_ADDR not set, falling back to poll-only

Fix: set in config.toml:

[node]
zmq_hashblock_addr = "tcp://127.0.0.1:28332"

And in bitcoin.conf:

zmqpubhashblock=tcp://127.0.0.1:28332

Bitcoin Core must be restarted after this change.

ZMQ connection refused / timeout

Bitcoin Core isn't listening on the ZMQ port. Diagnosis:

ss -tlnp | grep 28332
# Expected output: bitcoind listens on 0.0.0.0:28332 or 127.0.0.1:28332

If nothing: the bitcoin.conf line is missing or Bitcoin Core wasn't restarted.

If 0.0.0.0: ZMQ is exposed — often necessary with a Docker bridge (daemon and bitcoind in different containers). On a direct host tcp://127.0.0.1:28332 should be enough.

Stratum / miner connections

Workers reconnect-loop every few seconds

Symptom: many session ended with shares_accepted = 0 in the logs. Many miner-disconnect events in the notifier (or, with Phase 15 debounce, one every 30s).

Common causes:

  • Wrong worker address: a V1 miner submits an address the ShareValidator doesn't accept. Logs show mining.authorize with a bad address.
  • VarDiff too aggressive: the initial diff was too high, the miner can't produce shares within the target_seconds_per_share window, retargets down quickly, and some firmwares don't like rapid retargets. Fix: a higher min_diff or a lower initial_diff in [vardiff].
  • Auth rate limit kicks in: at >auths_per_sec auth attempts per IP you get rejected. In the log: auth rate-limited. For legitimate cases with multiple workers behind NAT: raise the rate limit.

Miner can't connect at all

# Is the pool port reachable?
nc -v pool.local 3333
# TLS port?
openssl s_client -connect pool.local:3334 -showcerts

If local is OK but external isn't: firewall / NAT. The UPnP wizard in setup (Phase 11) can open this automatically, but only if the FritzBox / router allows UPnP. Some ISP routers have UPnP off by default.

Notifier doesn't fire

notifier sink skipped: env var foo not set

At daemon start, the env vars for the sink aren't present. With systemd:

[Service]
EnvironmentFile=/etc/default/dvb-warppool

With /etc/default/dvb-warppool as a chmod-600 file:

TELEGRAM_BOT_TOKEN=123:abc...
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
POOL_SMTP_PASSWORD=...

For Docker: via -e KEY=val or an env-file in docker-compose.yml.

Test button shows err

Click Test in the admin UI → err badge. The specific error shows as a tooltip on the badge (hover). Common cases:

  • Telegram: bot not found — wrong bot_token. chat not found — wrong chat_id or the bot was removed from the chat.
  • Discord: Unknown Webhook — webhook was deleted.
  • Slack: invalid_payload — very rare; usually a typo in the webhook URL.
  • Email: Could not resolve host — wrong SMTP host. authentication failed — wrong password env. unable to connect: connection refused — wrong port or firewall.

Spam from miner-disconnect events

Per-worker debounce is 30s (WARPPOOL_DISCONNECT_DEBOUNCE_SECS). If that's too noisy: set the env var to 300 (5min).

If a single worker keeps disconnecting: that's a real problem on the miner side — check the logs on the miner hardware (the Bitaxe web interface has Logs; Antminer has SSH access).

Auto-update

Update fails: download/verify: sha256 mismatch

The asset on GitHub was changed between when you saw the release and downloaded it (rare), or you passed the wrong sha256. For POST /api/admin/update, always take the sha256 from the release notes file or from the GitHub API itself — never type it manually.

Update applied but daemon keeps restarting (StartLimitBurst)

The Phase 8f rollback hook fired. The systemd journal shows:

OnFailure=dvb-warppool-rollback.service triggered

rollback.sh copies the .backup back and runs systemctl restart. If the backup is also broken: install the old version manually or roll back from a snapshot.

cosign verify-blob failed

When cosign_verify=true is set in the update request: the signature doesn't match the asset. Possible causes:

  • The asset is authentic but the signature file is stale
  • The asset has been tampered with

The default is cosign_verify=false — only use cosign if you've explicitly configured the trust anchor (public key or Sigstore root).

Setup wizard

Most likely a permission issue. The setup wizard shows the exact path + suggested fix:

sudo usermod -a -G bitcoin warppool   # one-time
sudo chmod g+r ~/.bitcoin/.cookie     # after every Core restart

Cleaner: configure bitcoind with rpcauth=warppool:saltedhash and use user/pass mode instead of the cookie.

UPnP test "no gateway found"

The router has UPnP off, or the daemon is bound to the wrong interface. Some ISP routers (Vodafone, some FritzBoxes with a locked-down user account) don't allow UPnP from the outside.

Fix:

  • Enable UPnP in the router web interface
  • Alternatively: set port forwarding manually (3333/3334)

bitcoin.conf snippet suggests recommendations for keys that are already set

If the setup wizard says "add zmqpubhashblock=..." even though it's already there — usually the wrong conf path. Check bitcoin-cli -datadir=… getrpcinfo to see the datadir that's actually in use.

API / UI

/api/admin/* returns 401

Admin auth is configured but the token is missing from the request:

curl -H "Authorization: Bearer wpat_…" http://pool.local:18334/api/admin/notifier/sinks

Generate a token with dvb-warppool-cli token-create -n my-script — the raw token is shown only once.

/api/admin/* returns 503 "auth disabled"

secrets.toml has no admin_password_hash or jwt_secret. Fix:

dvb-warppool-cli hash-password

and paste the output into secrets.toml.

UI doesn't load — Failed to fetch /api/...

Direct --ui-dir mode or dev mode? In dev (pnpm dev), Vite runs with a proxy /api → http://127.0.0.1:18334. In production: the UI is served directly by the daemon via --ui-dir. Check the daemon startup log:

serving static UI from daemon ui_dir=/usr/share/dvb-warppool/ui

If not present: the --ui-dir flag is missing or the directory doesn't exist.

Vendor probes (Phase 22)

Miner is discovered via mDNS but no telemetry

Possible causes:

VendormDNS discoveryTelemetry probe
Bitaxe_bitaxe._tcp.local.✅ AxeOS HTTP /api/system/info
NerdNOS / NerdOctaxe_nerdminer._tcp.local.✅ AxeOS-compatible
Antminer S19/S21/S23❌ no mDNS✅ CGMiner socket 4028 — add manually in /admin/miners with vendor=antminer
Whatsminer M30S/M50✅ CGMiner socket — vendor=whatsminer
Avalon A12xx/A13xx standalone✅ CGMiner socket — vendor=avalon
Avalon Q (home miner)✅ CGMiner socket but its own field namesvendor=avalonq
Avalon A15xx (e.g. A1566)🟡 try vendor=avalon — if the field naming differs, please file an issue with cargo run -- probe --vendor avalon --host … output
Braiins OS / OS+🟡 via HTTP fallback when the hostname contains braiins* / bos-*✅ CGMiner socket 4028 with Braiins-specific field names (power_consumption_w, voltage, temp1..N) — vendor=braiins

vendor=avalon and vendor=avalonq are separate adapters — one matches MTavg/MTmax/GHS av, the other THSspd/TMax/Cur_Load. If you add a Q with vendor=avalon, lots of None values come back.

Manual add command

curl -X POST -H "Authorization: Bearer wpat_..." \
  -H "Content-Type: application/json" \
  -d '{"host":"192.168.1.42:4028","vendor":"avalonq","label":"avalonq-1"}' \
  http://pool.local:18334/api/admin/miners

Port 4028 is the CGMiner default. Some vendors reconfigure it — in that case, pass the correct port number.

Last resort

Daemon panicked and won't come up

Look at the logs. Common cases:

  • DB migration failed: sqlx::migrate throws on an inconsistent schema
  • Config file broken: TOML parse error with line number
  • Port taken: another pool / service on 3333

Rebuild storage DB from scratch

systemctl stop dvb-warppool
mv /var/lib/dvb-warppool/pool.db /var/lib/dvb-warppool/pool.db.broken
systemctl start dvb-warppool   # daemon creates a fresh DB and runs migrations

You will lose:

  • VarDiff snapshots per worker (every miner starts at initial_diff)
  • Aggregated hashrate history (raw shares > 1h are evicted anyway)
  • Audit log

Blocks-found is NOT the source of truth in the DB — those live in the Bitcoin blockchain itself. The block list is lazily re-populated on the first request via getblock RPCs.

See also