Appearance
FAQ / Troubleshooting
Networking
Nodes don't discover each other
- Verify the seed node is running and reachable:
ping <seed-host> - Check firewall rules: inter-node port (default
10000) must be open - Confirm
seed_.enabled_istrueon non-seed nodes - Verify
seed_.node_port_matches the seed'sports_.node_port_ - Check logs for
[svc] Connected to peermessages
Mesh is unstable / nodes keep dropping
- Increase
gossip_.suspect_timeout_s_(default: 10s) in high-latency networks - Ensure all nodes have synchronized clocks (NTP)
- Reduce
gossip_.cycle_interval_ms_for large clusters (50+ nodes)
JWT / Authentication
JWT token is rejected
- Verify the signature key matches between generator and configuration
- Check the token hasn't expired (
expclaim) - Ensure
requires_authmatches on the route — routes withrequires_auth = trueneed a valid JWT in theAuthorizationheader
Token generation fails
- Run
keys_generatorto create new signing and encryption keys - Confirm the base64 keys are correctly copied into
config.jwt_.keys_ - Tokens generated with
--grantsmust use valid JSON
Cache
Cache values not syncing between nodes
- Verify mesh networking is enabled (
app.run_mesh()) - Use
state->cache_set()instead ofcache.set()— the state-level method propagates to other nodes - Check that nodes are connected (see networking FAQ above)
- Anti-entropy sync runs periodically — changes are eventually consistent, not immediate
Cache key not found
- Check TTL: keys with
ttl_ms > 0expire automatically - Verify the key was set on the same node (read-your-writes is guaranteed only on the writing node)
- Use
cache.get_metadata(key)to check expiration and creation times
Database
Connection pool exhausted
- Increase
max_sizeincreate_pool()(default: 32) - Check for unclosed queries — each
pool->run()callback must complete before the connection returns to the pool - Use
pool->resize(new_max)to dynamically increase capacity
Query timeout
- Verify the MySQL server is reachable on the configured host:port
- Increase
read_timeout_seconds_inconfig.node_(default: 10s) - For long-running queries, break them into smaller chunks
General
App fails to start ("Address already in use")
The port is already occupied by another process. Either:
- Change the port in configuration
- Kill the process using the port:
lsof -ti :8080 | xargs kill
App fails to start (other errors)
Wrap app.run() in try-catch:
cpp
try {
app.run();
} catch (const std::exception& e) {
fmt::println(stderr, "Startup failed: {}", e.what());
return 1;
}Common causes:
- Invalid configuration file path
- TLS certificate files not found
- WAL directory not writable
- Boost/OpenSSL version mismatch
Logs show nothing
- Check that
ENABLE_SILENCEis not defined at compile time - Verify
config.logging_.enabled_istrue - Ensure the log scope includes the messages you want to see (
config.logging_.scope_bitset_) - By default,
LOG_INFO_SVC(config, ...)requires the"service"scope to be enabled
Next: CLI Tools.