Reference
Troubleshooting
New to acton-service?
Start with the homepage to understand what acton-service is, then explore Core Concepts for foundational explanations. See the Glossary for technical term definitions.
Find solutions to common problems when building services with acton-service.
Compilation Errors
Expected VersionedRoutes, found Router
Full error:
error[E0308]: mismatched types
--> src/main.rs:XX:XX
|
| ServiceBuilder::new().with_routes(app)
| ^^^ expected `VersionedRoutes`, found `Router`
Cause: You're trying to use a raw Router instead of VersionedRoutes.
Solution: Wrap your routes in VersionedApiBuilder:
// ❌ This won't compile
let app = Router::new().route("/hello", get(handler));
ServiceBuilder::new().with_routes(app)
// ✅ Do this instead
let routes = VersionedApiBuilder::new()
.with_base_path("/api")
.add_version(ApiVersion::V1, |router| {
router.route("/hello", get(handler))
})
.build_routes();
ServiceBuilder::new().with_routes(routes)
Cannot find type AppState in this scope
Full error:
error[E0412]: cannot find type `AppState` in this scope
Cause: Missing import or wrong feature flags.
Solution:
// Add to your imports
use acton_service::prelude::*;
// Or explicitly
use acton_service::state::AppState;
// And ensure you have the right features in Cargo.toml
Method database not found
Full error:
error[E0599]: no method named `database` found for struct `AppState`
Cause: Missing database feature flag.
Solution: Add the feature to your Cargo.toml:
[dependencies]
Could not find tonic in the list of imported crates
Cause: Missing grpc feature flag.
Solution: Add the feature:
[dependencies]
Trait IntoResponse is not implemented
Full error:
error[E0277]: the trait bound `MyType: IntoResponse` is not satisfied
Cause: Your handler is returning a type that doesn't implement IntoResponse.
Solution: Wrap it in Json or implement IntoResponse:
// ❌ This won't work
async fn handler() -> MyStruct {
MyStruct { field: "value" }
}
// ✅ Wrap in Json
async fn handler() -> Json<MyStruct> {
Json(MyStruct { field: "value" })
}
// ✅ Or use tuple for status code + json
async fn handler() -> (StatusCode, Json<MyStruct>) {
(StatusCode::OK, Json(MyStruct { field: "value" }))
}
Type System Issues
Cannot infer type for type parameter S
Cause: Axum can't infer the state type for your routes.
Solution: Be explicit about state:
// ❌ Ambiguous
let app = Router::new()
.route("/", get(handler));
// ✅ Explicit state type
let app: Router<AppState> = Router::new()
.route("/", get(handler));
Expected fn pointer, found closure
Cause: Handler function signature doesn't match Axum expectations.
Solution: Check your handler signature:
// ✅ Correct signatures
async fn simple_handler() -> &'static str { "ok" }
async fn json_handler() -> Json<MyType> { Json(value) }
async fn with_path(Path(id): Path<u64>) -> String { format!("ID: {}", id) }
async fn with_state(State(state): State<AppState>) -> String { "ok".to_string() }
Runtime Errors
Failed to bind to address 0.0.0.0:8080
Cause: Port 8080 is already in use.
Solutions:
Change the port (environment variable):
ACTON_SERVICE_PORT=9090 cargo runChange the port (config file):
[service] port = 9090Kill the process using port 8080:
# Find the process lsof -i :8080 # Kill it kill -9 <PID>
Database connection failed
Full error:
Error: Database connection failed: Connection refused
Cause: Database is not running or URL is incorrect.
Solutions:
Check if database is running:
# PostgreSQL pg_isready # Or check process ps aux | grep postgresVerify connection URL:
[database] url = "postgres://user:password@localhost:5432/dbname" # Make sure: user, password, host, port, and dbname are correctUse optional flag during development:
[database] url = "postgres://localhost/mydb" optional = true # Service starts even if DB is down
JWT validation failed
Cause: Invalid JWT token or wrong secret.
Solutions:
Check your secret:
// Make sure you're using the same secret for signing and validation let auth = JwtAuth::new("your-secret-key");Verify token format:
# Token should be: Bearer <token> curl -H "Authorization: Bearer eyJhbGc..." http://localhost:8080/api/v1/protectedCheck token expiration:
// Tokens might be expired // Check 'exp' claim in your JWT
Configuration Issues
Config file not found
Cause: Service can't find config.toml.
Solution: acton-service looks in these locations (in order):
./config.toml(current directory)~/.config/acton-service/{service_name}/config.toml/etc/acton-service/{service_name}/config.toml
# For development, create in current directory
cat > config.toml <<EOF
[service]
name = "my-service"
port = 8080
EOF
# For production
mkdir -p ~/.config/acton-service/my-service
cp config.toml ~/.config/acton-service/my-service/
Environment variables not working
Issue: ACTON_SERVICE_PORT=9090 doesn't change the port.
Cause: Environment variable naming or config priority.
Solution: Environment variables override config files:
# Correct format
ACTON_SERVICE_PORT=9090 cargo run
# Also works
export ACTON_SERVICE_PORT=9090
cargo run
# Check all ACTON_ variables
env | grep ACTON
Database Issues
Too many open connections
Cause: Database connection pool exhausted.
Solution: Configure pool size:
[database]
url = "postgres://localhost/mydb"
max_connections = 50 # Increase if needed (default: 10)
min_connections = 5 # Minimum pool size
Connection pool timeout
Cause: All connections are busy, waiting for one to become available.
Solutions:
Increase pool size:
[database] max_connections = 100Increase timeout:
[database] timeout_seconds = 30Check for connection leaks:
// Always use connections in short-lived scopes { let db = state.db().await.ok_or("Database not available")?; let result = sqlx::query!("SELECT * FROM users") .fetch_all(db) .await?; // Connection automatically returned to pool here }
Prepared statement already exists
Cause: SQLx query name collision.
Solution: Use unique query names or use query_as! without naming:
// ❌ Potential collision
let users = sqlx::query!("SELECT * FROM users").fetch_all(db).await?;
// ✅ Use query_as with explicit naming
let users = sqlx::query_as!(User, "SELECT id, name FROM users")
.fetch_all(db)
.await?;
Performance Issues
Slow startup time
Cause: Large number of dependencies or debug build.
Solutions:
Use release build:
cargo build --release ./target/release/my-serviceReduce features:
# Only enable what you needUse lazy initialization:
[database] lazy_init = true # Don't connect until first use
High memory usage
Cause: Too many connections or buffering.
Solutions:
Reduce connection pools:
[database] max_connections = 10 # Reduce from default [cache] max_pool_size = 5Check for memory leaks:
# Use valgrind or heaptrack valgrind --leak-check=full ./target/debug/my-service
Slow request processing
Cause: Database queries, blocking operations, or missing indices.
Solutions:
Profile your code:
# Use cargo-flamegraph cargo install flamegraph cargo flamegraph --bin my-serviceCheck database queries:
-- PostgreSQL: Enable query logging ALTER DATABASE mydb SET log_statement = 'all'; -- Look for slow queries SELECT query, calls, total_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;Use async properly:
// ❌ Don't block the async runtime async fn handler() { std::thread::sleep(Duration::from_secs(1)); // Bad! } // ✅ Use async sleep async fn handler() { tokio::time::sleep(Duration::from_secs(1)).await; // Good! }
Development Workflow
Cannot find example simple-api
Cause: Running examples from wrong directory.
Solution: Run from repository root:
# From acton-service repository root
cargo run --manifest-path=acton-service/Cargo.toml --example simple-api
# Not from acton-service/ subdirectory
Tests fail with "database connection refused"
Cause: Test database not running.
Solutions:
Use testcontainers (recommended):
#[tokio::test] async fn test_with_db() { // Automatically starts PostgreSQL in Docker let container = testcontainers::postgres::Postgres::default(); // ... test code }Mock the database:
// Use a mock state for unit tests let state = AppState::default();Set up test database:
# Start a test database docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=test postgres:16 # Use different port for tests ACTON_DATABASE_URL=postgres://postgres:test@localhost:5433/test cargo test
Hot reload not working
Issue: Want to auto-restart on code changes.
Solution: Use cargo-watch:
# Install cargo-watch
cargo install cargo-watch
# Auto-reload on changes
cargo watch -x run
# Auto-reload with custom command
cargo watch -x 'run --example simple-api'
Still Stuck?
Enable debug logging
RUST_LOG=debug cargo run
Or set in config:
[service]
log_level = "debug"
Check the examples
The examples directory has working code for most features.
Get help
- GitHub Issues
- API Documentation
- Check Tutorial for step-by-step guides
Report a bug
If you've found a bug, please include:
- Your
Cargo.tomldependencies - Full error message
- Minimal reproduction code
- Rust version (
rustc --version) - OS and version
# Quick diagnostic info
rustc --version
cargo --version
uname -a