Troubleshooting
Common problems and how to fix them.
This guide covers common issues you might encounter when using Resonate and how to resolve them.
If your problem isn't listed here, check the Errors reference for error codes or ask in Discord.
Server won't start#
Database connection failures#
Symptoms:
- Server fails to start with connection errors
- Logs show
failed to connect to databaseor similar
Causes:
- PostgreSQL not running
- Wrong connection credentials
- Network/firewall blocking connection
- Database doesn't exist
Solutions:
- Check PostgreSQL is running:
# PostgreSQL status
pg_isready -h localhost -p 5432
# For managed services, check cloud console- Verify connection string:
[storage]
type = "postgres"
[storage.postgres]
url = "postgres://resonate:secret@localhost:5432/resonate"Or set RESONATE_STORAGE__POSTGRES__URL in the environment. Check the host, port, database, user, and password all match what your Postgres instance expects.
- Create database if missing:
psql -h localhost -U postgres -c "CREATE DATABASE resonate;"- Check firewall/security groups:
- Ensure server can reach database on port 5432
- Check cloud security group rules
- Verify VPC/network configuration
Port already in use#
Symptoms:
- Server fails to start
- Logs show
address already in useorbind: address already in use
Cause: Another process is using port 8001 (HTTP).
Solutions:
- Find what's using the port:
# macOS/Linux
lsof -i :8001
# Kill the process if needed
kill -9 <PID>- Use a different port:
Pass
--server-porttoresonate serveto bind a different port:
resonate serve --server-port 8003Configuration file errors#
Symptoms:
- Server fails to start
- Logs show a TOML parse error from
figmentor an unknown field name
Cause:
Invalid TOML syntax in resonate.toml, or a field name that doesn't match the schema.
Solutions:
-
Validate TOML syntax with any TOML linter, or paste it into toml-lint.com.
-
Check section and field names against Run a server. Sections are nested with dots:
[storage.postgres], not[storage_postgres]. -
Check env var nesting. Environment variables use the
RESONATE_prefix and__(double underscore) for nesting:
# WRONG — single underscore
RESONATE_STORAGE_POSTGRES_URL=...
# RIGHT — double underscore between sections
RESONATE_STORAGE__POSTGRES__URL=...Workers not receiving tasks#
Workers not connecting#
Symptoms:
- Workers start but never process tasks
- No worker registration in server logs
- Tasks remain pending indefinitely
Causes:
- Wrong server URL
- Network/firewall blocking connection
- Server not running
- Authentication misconfigured
Solutions:
- Verify server URL:
const resonate = new Resonate({
url: "http://resonate-server:8001", // Must match server address
group: "workers",
});- Test connectivity:
# From worker machine, test server reachability
curl -s -o /dev/null -w "%{http_code}\n" http://resonate-server:8001/health
# Should return 200 when the server is alive- Check authentication: If server has auth enabled, workers must provide credentials:
const resonate = new Resonate({
url: "http://resonate-server:8001",
group: "workers",
token: "your-jwt-token",
});- Check server logs:
# Look for worker registration messages
resonate serve --level debug
# Should see: "worker registered" or similarTasks not reaching workers#
Symptoms:
- Workers connected but not processing tasks
- Tasks created but remain pending
- No task distribution happening
Causes:
- Wrong worker group name
- Worker polling misconfigured
- Task routing rules don't match workers
Solutions:
- Verify group names match:
// When registering worker:
const resonate = new Resonate({
group: "workers", // Note the group name
});
// When creating task:
resonate.rpc(
taskId,
"processOrder",
data,
resonate.options({
target: "poll://any@workers", // Must match worker group
})
);- Check worker is polling: Workers must actively poll for tasks. Ensure your worker code calls functions that poll:
// Worker polls when you register functions
resonate.register("processOrder", async (ctx, data) => {
// Task execution
});
// Worker polls automatically after registration- Inspect promise state:
# Query promises to see if tasks are being created
curl http://localhost:8001/promises?state=pending
# Check if tasks exist for those promises
curl http://localhost:8001/tasks?state=pendingPromises not resolving#
Promise stuck in pending state#
Symptoms:
- Promise created but never completes
- No worker picks up the task
resonate.promises.get()showsstate: "pending"indefinitely
Causes:
- No workers available for the task's group
- Worker crashed mid-execution and task not reassigned
- Task timeout not configured (waits forever)
- Routing misconfiguration
Solutions:
- Confirm workers are running:
# Check worker processes
ps aux | grep worker
# In Kubernetes:
kubectl get pods -l app=resonate-worker- Check promise/task state:
# Get promise details
curl http://localhost:8001/promises/{promiseId}
# Check if task exists
curl http://localhost:8001/tasks?promiseId={promiseId}- Set task timeouts:
resonate.rpc(
taskId,
"processOrder",
data,
resonate.options({
target: "poll://any@workers",
timeout: 60000, // 60 second timeout
})
);- Check worker heartbeats: If worker crashed, server should detect via heartbeat timeout (default: 60s) and reassign. Check server logs for heartbeat failures.
Promise failed but retry not working#
Symptoms:
- Promise fails once and doesn't retry
- Expected automatic retry but it didn't happen
Cause: Resonate doesn't automatically retry failed promises unless you configure retry logic.
Solutions:
- Implement retry logic explicitly:
async function processOrderWithRetry(ctx, data) {
let attempts = 0;
const maxAttempts = 3;
while (attempts < maxAttempts) {
try {
const result = await ctx.run(() => processOrder(data));
return result;
} catch (error) {
attempts++;
if (attempts >= maxAttempts) throw error;
await ctx.sleep(1000 * attempts); // Exponential backoff
}
}
}- Check error type: Some errors shouldn't retry (e.g., invalid input). Handle appropriately:
catch (error) {
if (error.code === "INVALID_INPUT") {
throw error; // Don't retry
}
// Retry for transient errors
}Performance issues#
Slow task execution#
Symptoms:
- Tasks complete but take longer than expected
- High latency between task creation and completion
Causes:
- Not enough workers (tasks queue up)
- Worker resource constraints (CPU/memory)
- Database performance issues
- Network latency
Solutions:
- Scale workers horizontally:
# Docker Compose
docker-compose up -d --scale worker=10
# Kubernetes
kubectl scale deployment resonate-workers --replicas=20See Scaling for details.
- Monitor worker resources:
# Check CPU/memory usage
top
htop
# Kubernetes:
kubectl top pods -l app=resonate-worker- Optimize database:
- Add indexes for frequently queried promise/task fields
- Increase PostgreSQL connection pool size
- Use managed PostgreSQL with IOPS scaling
- Check network latency:
# Measure round-trip time to server
ping resonate-server
# Test HTTP latency
time curl -s http://resonate-server:8001/healthHigh database load#
Symptoms:
- Slow promise creation/resolution
- Database CPU/IOPS maxed out
- Connection pool exhausted
Causes:
- Too many concurrent promises
- Inefficient queries (missing indexes)
- Insufficient database resources
Solutions:
- Upgrade database resources:
- Increase CPU/RAM
- Add IOPS capacity (for cloud databases)
- Use managed PostgreSQL with auto-scaling
- Tune connection pool:
[storage.postgres]
url = "postgres://resonate:secret@localhost:5432/resonate"
pool_size = 50 # Increase pool size (default: 10)-
Add database indexes: Check PostgreSQL slow query log and add indexes for common queries.
-
Batch operations: If creating many promises, batch them when possible to reduce database round-trips.
Authentication issues#
Unauthorized errors#
Symptoms:
- Workers can't connect
- API requests return
401 Unauthorized - Logs show authentication failures
Causes:
- Wrong credentials
- Auth enabled on server but not configured in client
- Token expired (JWT)
Solutions:
- Verify credentials:
const resonate = new Resonate({
url: "http://resonate-server:8001",
token: "your-jwt-token", // Check this matches server config
});- Check server auth config:
The server uses JWT bearer auth signed with an Ed25519 key. Start the server with the public key path:
resonate serve --auth-publickey /etc/resonate/auth/public.pemOr in resonate.toml:
[auth]
publickey = "/etc/resonate/auth/public.pem"In the SDK, pass a JWT signed by the matching private key:
const resonate = new Resonate({
url: "http://resonate-server:8001",
token: process.env.RESONATE_TOKEN,
});- For JWT tokens, verify:
- Token hasn't expired
- Signature was produced with the private key matching the server's public key
iss/audclaims match what the server expects (if configured)
See Security for the full auth setup.
Development workflow issues#
Changes not taking effect#
Symptoms:
- Code changes don't appear when running
- Old behavior persists after updates
Causes:
- Using wrong binary (old version still running)
- Cache issues
- Docker image not rebuilt
Solutions:
- Verify process is new:
# Kill old processes
pkill -f resonate
# Restart with fresh binary
resonate serve- Rebuild Docker images:
docker-compose build --no-cache
docker-compose up -d- Clear SDK caches (if applicable):
# Node.js
rm -rf node_modules && npm install
# Python
rm -rf __pycache__ && pip install -r requirements.txtSQLite "database is locked" errors#
Symptoms:
- SQLite errors about locked database
- Concurrent access failures
Cause: SQLite doesn't handle high concurrency well. Multiple processes/threads trying to write simultaneously.
Solution: Use PostgreSQL for any deployment with concurrent writers:
[storage]
type = "postgres"
[storage.postgres]
url = "postgres://resonate:secret@localhost:5432/resonate"SQLite is best for development and single-tenant deployments where there is no concurrent write contention against the server.
Getting more help#
If these troubleshooting steps don't resolve your issue:
- Check error codes: See Errors for detailed error information
- Enable debug logging:
resonate serve --level debug-
Collect diagnostics:
- Server logs
- Worker logs
- Promise/task state from API
- Database connection status
- Network connectivity tests
-
Ask in Discord: Share diagnostics in the Resonate Discord
-
File a bug: If you've found a bug, open an issue on GitHub
Quick diagnostic checklist#
When debugging, check these in order:
- Server running and reachable (
curl http://server:8001/healthreturns200) - Storage reachable (
curl http://server:8001/readyreturns200) - Workers registered with server (check logs)
- Worker group names match task routing
- Authentication configured (if enabled)
- Network/firewall allows communication
- Adequate resources (CPU, memory, IOPS)
- No port conflicts
-
resonate.tomlsyntax valid (and env-var nesting uses__) - Using recent Resonate version
Most issues fall into one of these categories. Work through the checklist systematically.