Troubleshooting
This page covers common issues you may encounter when running bext, along with diagnostic commands and fixes.
Diagnostic Commands
Start here. These commands give you a snapshot of the system state:
# Pre-flight check: validates config, checks ports, TLS paths, permissions
bext-server check
# Show loaded configuration (merged from file + env + defaults)
bext-server config show
# Print the route table for the current app
bext-server routes
# Cache hit rates, sizes, and per-app breakdown
bext-server cache stats
# Running apps, render worker count, memory usage
bext-server ps
# Health check (DB, cache, isolates, plugins)
bext-server health
# Current metrics snapshot
bext-server metrics
For verbose output, add --log-level debug or --log-level trace:
bext-server --log-level debug run
TLS Certificate Errors
ACME challenge failing
Symptom: error: ACME HTTP-01 challenge failed for domain.com
Causes and fixes:
1. Port 80 not reachable. ACME HTTP-01 requires incoming traffic on port 80. Check firewall rules and confirm bext is listening on port 80 (it binds automatically when tls.auto_acme = true).
# Check if port 80 is open
ss -tlnp | grep :80
2. DNS not pointing to this server. The domain must resolve to the server's public IP. Verify with:
dig +short domain.com
curl -I http://domain.com/.well-known/acme-challenge/test
3. Another process on port 80. If nginx or Apache is already bound to port 80, stop it or use bext's nginx takeover mode.
Certificate not renewing
Certificates auto-renew 30 days before expiry. If renewal fails, check the logs:
bext-server --log-level debug run 2>&1 | grep -i acme
Common cause: the ACME account rate limit was hit. Wait 1 hour and restart.
Using custom certificates
If auto-ACME is not suitable, provide cert files directly:
[tls]
auto_acme = false
cert_path = "/etc/ssl/certs/domain.pem"
key_path = "/etc/ssl/private/domain.key"
Ensure the files are readable by the bext process user and the certificate chain is complete (leaf + intermediates).
SSR Failures
V8 pool exhaustion
Symptom: Requests queue up, latency spikes, logs show jsc pool: all workers busy, waiting...
Fix: Increase the render worker count:
[render]
workers = 8 # default is 4, increase for high-traffic SSR
Monitor with render_pool_active and render_pool_idle metrics. If render_pool_idle consistently drops to 0, add more workers.
SSR render timeout
Symptom: error: SSR render timed out after 10000ms
Your React components are taking too long to render server-side. Common causes:
- Fetching data inside components during SSR (move to getServerSideProps or server actions)
- Infinite loops in rendering logic
- Very large component trees
Increase the timeout as a stopgap, then fix the underlying issue:
[render]
timeout_ms = 15000 # default is 10000
Out of memory (OOM) kills
Symptom: render workers getting killed, logs show jsc worker OOM: exceeded 256MB limit
Each render worker has a memory limit to prevent a single render from consuming all RAM:
[render]
worker_memory_limit_mb = 512 # default is 256
If renders consistently hit this limit, audit your SSR code for memory leaks (large data structures, unbounded caches in module scope).
Cache Issues
Stale content after deploy
Symptom: Old content still being served after deploying new code.
The ISR cache and compression cache need to be cleared:
# Purge all caches for an app
bext-server cache purge --app my-app
# Or purge everything
bext-server cache purge --all
If using Redis L2, the purge command clears both L1 and L2. Automated deploys via bext deploy purge caches automatically.
Cache stampede under load
Symptom: High CPU spikes when cache entries expire under heavy traffic.
bext's stampede guard coalesces concurrent requests for the same uncached URL. Verify it is active:
bext-server cache stats --json | jq '.stampede_coalesced'
If stampede is still occurring, ensure stale-while-revalidate (SWR) is configured. SWR serves the stale entry while one background request refreshes it:
[cache.isr]
default_swr_ms = 3_600_000 # serve stale for up to 1 hour while revalidating
ISR cache growing too large on disk
The ISR cache is in-memory by default (bounded by max_entries). If you have Redis L2 enabled, Redis may grow. Set a TTL on L2 entries:
[cache.isr]
l2_ttl_ms = 300_000 # Redis entries expire after 5 minutes
Plugin Issues
Plugin timeout
Symptom: warn: plugin "my-plugin" timed out after 5000ms
Plugins have a default execution timeout to prevent runaway code:
[plugins]
timeout_ms = 10000 # increase from default 5000
For WASM plugins, check if the plugin is doing expensive I/O. For QuickJS plugins, check for infinite loops.
Plugin crash / panic
Symptom: error: plugin "my-plugin" panicked: ...
Plugins run in isolated sandboxes, so a crash does not take down the server. The plugin is disabled for subsequent requests until reloaded.
Reload plugins without restarting the server:
kill -HUP $(cat /run/bext.pid)
Check the plugin's logs at debug level to see the panic backtrace.
Plugin memory limits
WASM plugins have configurable memory limits:
[plugins.wasm]
max_memory_mb = 64 # per-plugin memory limit
High CPU Usage
Transform pipeline
If CPU is high and the http_request_duration_seconds metric shows long tails, the transform pipeline (TypeScript compilation, JSX transforms) may be the bottleneck. In production, transforms should happen at build time, not per-request:
# Build once for production
bext-server build
# Then run the built output
bext-server run
Image optimization
On-the-fly image resizing is CPU-intensive. Enable the image cache to avoid reprocessing:
[image]
cache = true
cache_dir = "/var/cache/bext/images"
max_width = 2048
quality = 80
Pre-generate common sizes during build for high-traffic images.
Disk Space
Log files growing
Enable log rotation:
[logging]
rotate = true
rotate_max_size_mb = 100
rotate_max_files = 10
rotate_compress = true
Or use logrotate externally:
/var/log/bext/*.log {
daily
rotate 14
compress
missingok
notifempty
postrotate
kill -USR1 $(cat /run/bext.pid)
endscript
}
The USR1 signal tells bext to reopen log files after rotation.
Image cache growth
Set a maximum size for the image optimization cache:
[image]
cache_max_size_mb = 2048 # evict LRU entries above 2GB
Getting Help
If these steps do not resolve your issue:
1. Run bext-server check --fail-on-warnings and include the output
2. Set log level to debug and capture the relevant log lines
3. Check the GitHub Issues for known problems
4. Open a new issue with your bext version (bext-server version), OS, config file (redact secrets), and the full error output