Troubleshooting
This guide covers the most common errors you’ll encounter when operating Containment Chamber, with clear causes and fixes for each.
Diagnostic Commands
Section titled “Diagnostic Commands”Before diving into specific errors, these commands help narrow down the problem:
# Is the signer running?curl http://localhost:9000/upcheck
# Which keys are loaded?curl http://localhost:9000/api/v1/eth2/publicKeys
# Verbose loggingRUST_LOG=containment_chamber=debug containment-chamber -c config.yamlHTTP 412 — Slashing Protection Triggered
Section titled “HTTP 412 — Slashing Protection Triggered”Cause: EIP-3076 anti-slashing refused the signing request because it would produce a slashable message (double vote or surround vote).
This is expected behavior. The signer is protecting your validators from being slashed.
Common triggers:
- Clock drift between your beacon node and the signer
- Restarting after a crash where the beacon node replays recent duties
- Importing a slashing protection database from the wrong source or validator
What to check:
- Ensure NTP is configured and clocks are synchronized
- If migrating validators, export the slashing DB from the previous signer and import it before starting
- See Anti-Slashing Protection for backend configuration
HTTP 404 — Key Not Found
Section titled “HTTP 404 — Key Not Found”Cause: The requested public key isn’t loaded. The signer doesn’t have the keystore for this validator.
Fix:
- Verify the key is actually loaded:
Terminal window curl http://localhost:9000/api/v1/eth2/publicKeys - Check your
key_sources.filesystem.pathsconfiguration points to the correct directory - Verify file permissions: the keystore files must be readable by the service user
- Check startup logs for load errors (wrong password, corrupt keystore, bad filename)
For encrypted keystores: each .json keystore file needs a matching YAML descriptor and .password file alongside it. The YAML descriptor’s keystorePasswordFile field must point to the correct password file. See the Key Formats guide for the expected directory structure.
HTTP 401 — Unauthorized
Section titled “HTTP 401 — Unauthorized”Cause: auth_policies are configured, but the request arrived without an authentication token. When policies exist and no unauthenticated_policy is defined, all unauthenticated requests are rejected.
Fix: Add the token to your client’s signer URL using HTTP Basic auth:
http://x:your-token-here@signer:9000The username (x) is ignored. Only the password portion matters.
See Auth Policies for full configuration details.
HTTP 403 — Forbidden
Section titled “HTTP 403 — Forbidden”Cause: The token is valid, but the associated policy denies this specific request. The key isn’t in allowed_keys, the operation is blocked by allowed_signing_operations / denied_signing_operations, or the route’s scope is not in allowed_scopes.
Fix:
- Check which policy the token maps to in your
auth_policiesconfig - Verify the requested public key is listed in
allowed_keys(if set) - Verify the operation isn’t blocked by
denied_signing_operationsor missing fromallowed_signing_operations - Verify the route’s scope is accessible via
allowed_scopes/denied_scopes
An unknown token also returns 403. Double-check the token value matches your config exactly.
See Auth Policies for the full policy behavior matrix.
HTTP 503 — Service Unavailable
Section titled “HTTP 503 — Service Unavailable”Cause: The signing request queue is full. Too many concurrent requests exceeded the buffer capacity.
Fix: Increase the queue size or concurrency limit in your config:
signing_queue_buffer_size: 5000 # default: 3000max_concurrent_signing_jobs: 200 # default: 100If you’re consistently hitting 503s, you may be running too many validators for a single instance. Consider scaling horizontally with a shared PostgreSQL anti-slashing backend.
Keys Not Loading
Section titled “Keys Not Loading”Keystores can fail to load silently at startup. Run with debug logging to see what’s happening:
RUST_LOG=containment_chamber=debug containment-chamber -c config.yamlCommon causes:
key_sources.filesystem.pathsdirectory doesn’t exist or isn’t readable- Encrypted keystores missing their password file
- Password file contains trailing whitespace or newlines
- Keystore JSON is malformed or uses an unsupported format
- File permissions too restrictive for the service user
Quick checklist:
- Does the directory exist?
ls -la /path/to/keystores/ - Are keystore files readable? Check ownership and permissions
- For encrypted keystores, is the password file present and correct?
- Do the logs show any errors during key loading?
Startup Failures
Section titled “Startup Failures”Containment Chamber validates all configuration at startup and prints clear error messages to stderr.
Common validation errors:
- “cannot set both allowed_signing_operations and denied_signing_operations” — pick one approach per policy
- “cannot set both allowed_scopes and denied_scopes” — pick one approach per policy
- “allowed_signing_operations is meaningless when sign scope is denied” — remove signing op restrictions or allow the
signscope - “invalid token” — tokens must be at least 16 characters, alphanumeric and dashes only
- “same token” — two policies share the same token value
- “unknown signing operation” — typo in an operation name (check the valid operations list)
- “invalid public key format” —
allowed_keysentries must be 0x-prefixed, 96-character hex strings
Environment variable issues:
- Tokens using
env:VAR_NAMEsyntax fail if the variable isn’t set - Environment variables use
CONTAINMENT_prefix with__for nesting (e.g.,CONTAINMENT_ANTISLASHING__BACKEND)
Still Stuck?
Section titled “Still Stuck?”If none of the above matches your issue:
- Run with
RUST_LOG=containment_chamber=debugand check the full log output - Verify your config file parses correctly by starting with a minimal configuration
- Check the Configuration Reference for all available options