Configuration Guide¶
Errorworks servers are configured through three layered methods: presets, YAML config files, and CLI flags. Each layer overrides the one below it, giving you fine-grained control without rewriting entire configuration files.
Configuration Precedence¶
From highest to lowest priority:
Each layer is deep-merged into the one below. You only need to specify the fields you want to change -- everything else inherits from the lower layer.
Example: How Layers Combine¶
Given this preset (realistic):
error_injection:
rate_limit_pct: 5.0
capacity_529_pct: 2.0
burst:
enabled: true
interval_sec: 60
duration_sec: 5
latency:
base_ms: 100
jitter_ms: 50
And this config file (my-config.yaml):
And this CLI flag:
The final configuration is:
error_injection:
rate_limit_pct: 25.0 # CLI flag wins
capacity_529_pct: 2.0 # From preset (config file didn't touch it)
burst:
enabled: true # From preset (preserved by deep merge)
interval_sec: 30 # Config file overrode preset
duration_sec: 5 # From preset (preserved by deep merge)
latency:
base_ms: 100 # From preset
jitter_ms: 50 # From preset
Note
Deep merge is recursive. When the config file sets burst.interval_sec, it does not reset burst.enabled or burst.duration_sec to their defaults. Only the fields you explicitly set are changed.
YAML Config File¶
Pass a YAML file with --config=path/to/config.yaml. The file structure mirrors the configuration models.
ChaosLLM Full Example¶
server:
host: "127.0.0.1"
port: 8000
workers: 1
admin_token: "my-secret-token" # Auto-generated if omitted
metrics:
database: "file:chaosllm-metrics?mode=memory&cache=shared"
timeseries_bucket_sec: 1
response:
mode: random # random | template | echo | preset
allow_header_overrides: true
max_template_length: 10000
random:
min_words: 20
max_words: 100
vocabulary: english # english | lorem
template:
body: '{"result": "ok"}'
preset:
file: ./responses.jsonl
selection: random # random | sequential
latency:
base_ms: 100
jitter_ms: 50
error_injection:
# Selection strategy
selection_mode: priority # priority | weighted
# HTTP errors (0-100 percentage)
rate_limit_pct: 5.0
capacity_529_pct: 2.0
service_unavailable_pct: 0.5
bad_gateway_pct: 0.1
gateway_timeout_pct: 0.2
internal_error_pct: 0.2
forbidden_pct: 0.0
not_found_pct: 0.0
# Retry-After header range for rate limit errors
retry_after_sec: [1, 5]
# Connection failures
timeout_pct: 0.2
timeout_sec: [30, 60]
connection_reset_pct: 0.1
connection_failed_pct: 0.0
connection_failed_lead_sec: [2, 5]
connection_stall_pct: 0.0
connection_stall_start_sec: [0, 2]
connection_stall_sec: [30, 60]
slow_response_pct: 1.0
slow_response_sec: [5, 15]
# Malformed responses
invalid_json_pct: 0.1
truncated_pct: 0.1
empty_body_pct: 0.0
missing_fields_pct: 0.1
wrong_content_type_pct: 0.0
# Burst patterns
burst:
enabled: true
interval_sec: 60
duration_sec: 5
rate_limit_pct: 50
capacity_pct: 30
ChaosWeb Full Example¶
server:
host: "127.0.0.1"
port: 8200
workers: 1
admin_token: "my-secret-token"
metrics:
database: "file:chaosweb-metrics?mode=memory&cache=shared"
timeseries_bucket_sec: 1
content:
mode: random # random | template | echo | preset
allow_header_overrides: true
max_template_length: 10000
default_content_type: "text/html; charset=utf-8"
random:
min_words: 100
max_words: 500
vocabulary: english
template:
body: "<html><body><h1>{{ path }}</h1><p>{{ random_words(100, 300) }}</p></body></html>"
preset:
file: ./pages.jsonl
selection: random
latency:
base_ms: 300
jitter_ms: 150
error_injection:
selection_mode: priority
# HTTP errors
rate_limit_pct: 5.0
forbidden_pct: 3.0
not_found_pct: 2.0
gone_pct: 0.0
payment_required_pct: 0.0
unavailable_for_legal_pct: 0.0
service_unavailable_pct: 1.0
bad_gateway_pct: 0.2
gateway_timeout_pct: 0.3
internal_error_pct: 0.5
retry_after_sec: [5, 30]
# Connection failures
timeout_pct: 0.5
timeout_sec: [10, 30]
connection_reset_pct: 0.2
connection_stall_pct: 0.0
connection_stall_start_sec: [0, 2]
connection_stall_sec: [30, 60]
slow_response_pct: 5.0
slow_response_sec: [3, 10]
incomplete_response_pct: 0.0
incomplete_response_bytes: [100, 1000]
# Content malformations
wrong_content_type_pct: 1.0
encoding_mismatch_pct: 1.0
truncated_html_pct: 0.5
invalid_encoding_pct: 0.0
charset_confusion_pct: 0.0
malformed_meta_pct: 0.0
# Redirects
redirect_loop_pct: 0.0
max_redirect_loop_hops: 10
ssrf_redirect_pct: 0.0
# Burst patterns
burst:
enabled: true
interval_sec: 60
duration_sec: 8
rate_limit_pct: 40
forbidden_pct: 30
ChaosBlob Full Example¶
server:
host: "127.0.0.1"
port: 8300
workers: 1
admin_token: "my-secret-token"
metrics:
database: "file:chaosblob-metrics?mode=memory&cache=shared"
timeseries_bucket_sec: 1
storage:
max_object_bytes: 10485760
default_content_type: "application/octet-stream"
latency:
base_ms: 150
jitter_ms: 75
error_injection:
selection_mode: priority
# S3 HTTP errors
slow_down_pct: 4.0
access_denied_pct: 0.5
not_found_pct: 1.0
service_unavailable_pct: 0.8
internal_error_pct: 0.2
bad_gateway_pct: 0.2
gateway_timeout_pct: 0.3
retry_after_sec: [2, 20]
# Connection failures
timeout_pct: 0.3
timeout_sec: [10, 30]
connection_reset_pct: 0.2
connection_stall_pct: 0.0
connection_stall_start_sec: [0, 2]
connection_stall_sec: [30, 60]
slow_response_pct: 3.0
slow_response_sec: [2, 8]
# Object and list corruption
truncated_body_pct: 0.5
wrong_content_length_pct: 0.3
checksum_mismatch_pct: 0.5
metadata_corruption_pct: 0.3
stale_list_pct: 3.0
malformed_xml_pct: 0.2
# Burst patterns
burst:
enabled: true
interval_sec: 90
duration_sec: 10
slow_down_pct: 35.0
service_unavailable_pct: 10.0
ChaosSMTP Full Example¶
smtp:
host: "127.0.0.1"
port: 2525 # Use 0 in tests for an ephemeral loopback port
hostname: "chaossmtp.local"
data_size_limit: 10485760
enable_smtputf8: true
require_starttls: false # true is reserved until TLS context support exists
admin:
enabled: true
host: "127.0.0.1"
port: 8525
admin_token: "my-secret-token" # Auto-generated if omitted
metrics:
database: "file:chaossmtp-metrics?mode=memory&cache=shared"
timeseries_bucket_sec: 1
capture:
mode: metadata # discard | metadata | full
max_message_bytes: 1048576
max_messages: 1000
latency:
base_ms: 120
jitter_ms: 60
error_injection:
selection_mode: priority
# SMTP-stage failures
rate_limit_pct: 3.0
mail_from_tempfail_pct: 0.0
mail_from_reject_pct: 0.0
rcpt_to_tempfail_pct: 4.0
rcpt_to_reject_pct: 0.0
data_tempfail_pct: 3.0
data_reject_pct: 1.0
accept_then_drop_pct: 0.0
malformed_reply_pct: 0.0
wrong_reply_code_pct: 0.0
connection_reset_pct: 0.0
connection_stall_pct: 0.0
slow_response_pct: 2.0
# Delay ranges for selected SMTP behavior
# retry_after_sec is validated config; current SMTP replies do not emit a Retry-After header.
retry_after_sec: [1, 30]
connection_stall_sec: [30, 60]
slow_response_sec: [3, 15]
# Burst patterns
burst:
enabled: true
interval_sec: 60
duration_sec: 8
rcpt_to_tempfail_pct: 50.0
rate_limit_pct: 40.0
Configuration Sections¶
Server (ChaosLLM and ChaosWeb)¶
| Field | Type | Default (LLM/Web/Blob) | Description |
|---|---|---|---|
host |
string | 127.0.0.1 |
Bind address |
port |
int | 8000 / 8200 / 8300 |
Listen port |
workers |
int | 1 |
Uvicorn worker count. Values > 1 require a file-backed metrics database. |
admin_token |
string | auto-generated | Bearer token for /admin/* endpoints |
Warning
Binding to 0.0.0.0 or :: is blocked by default. Errorworks servers are testing tools and should not be exposed to the network. Set allow_external_bind: true at the top level to override this safety check.
SMTP Listener and Admin Sidecar (ChaosSMTP)¶
ChaosSMTP separates the SMTP listener from the HTTP admin sidecar:
| Field | Type | Default | Description |
|---|---|---|---|
smtp.host |
string | 127.0.0.1 |
SMTP listener bind address |
smtp.port |
int | 2525 |
SMTP listener port. Config accepts 0 for an ephemeral test port. |
smtp.hostname |
string | chaossmtp.local |
Hostname announced to SMTP clients |
smtp.data_size_limit |
int | 10485760 |
Maximum SMTP DATA size in bytes |
smtp.enable_smtputf8 |
bool | true |
Enable SMTPUTF8 extension support |
smtp.require_starttls |
bool | false |
Reserved for future TLS context support. true is rejected. |
admin.enabled |
bool | true |
Run the HTTP admin sidecar |
admin.host |
string | 127.0.0.1 |
Admin sidecar bind address |
admin.port |
int | 8525 |
Admin sidecar port |
admin.admin_token |
string | auto-generated | Bearer token for /admin/* endpoints |
chaossmtp show-config redacts admin.admin_token, but admin endpoints still require the bearer token at runtime.
Metrics¶
| Field | Type | Default | Description |
|---|---|---|---|
database |
string | in-memory (shared) | SQLite database path or URI |
timeseries_bucket_sec |
int | 1 |
Time-series aggregation bucket size in seconds |
Use --database=/path/to/metrics.db for persistent file-backed storage. See the Metrics Guide for details.
Default in-memory database URIs are service-specific:
- ChaosLLM:
file:chaosllm-metrics?mode=memory&cache=shared - ChaosWeb:
file:chaosweb-metrics?mode=memory&cache=shared - ChaosSMTP:
file:chaossmtp-metrics?mode=memory&cache=shared
Latency¶
| Field | Type | Default | Description |
|---|---|---|---|
base_ms |
int | 50 |
Base latency added to every response (milliseconds) |
jitter_ms |
int | 30 |
Random jitter range (+/- milliseconds) |
The actual delay per request is (base_ms + random(-jitter_ms, +jitter_ms)) / 1000 seconds, clamped to zero.
SMTP Capture¶
| Field | Type | Default | Description |
|---|---|---|---|
capture.mode |
discard \| metadata \| full |
metadata |
How accepted SMTP messages are stored |
capture.max_message_bytes |
int | 1048576 |
Maximum bytes stored in full capture mode |
capture.max_messages |
int | 1000 |
Maximum captured messages kept in memory |
discard records metrics only. metadata stores the envelope, subject, and safe headers. full stores base64-encoded message bytes up to max_message_bytes. Metadata and full capture keep at most max_messages records and drop the oldest first.
Runtime Config Updates¶
You can update the configuration while the server is running via POST /admin/config:
# Increase rate limiting at runtime
curl -X POST http://localhost:8000/admin/config \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"error_injection": {
"rate_limit_pct": 25.0
}
}'
# View current config
curl http://localhost:8000/admin/config \
-H "Authorization: Bearer $ADMIN_TOKEN"
Runtime updates use the same deep-merge behavior as config file layering. You only send the fields you want to change -- everything else is preserved.
ChaosSMTP runtime updates cover error_injection, capture, and latency. Listener binding, admin binding, metrics database, and admin token changes require restarting the server with a new config.
How Runtime Updates Work¶
The server uses immutable Pydantic models (frozen=True) for all configuration. When you POST an update:
- The current config is serialized to a dict
- Your update is deep-merged into it
- New immutable model instances are created and validated
- The new components (error injector, response/content/capture component, latency simulator) are built
- References are atomically swapped under a lock
Requests that are already in-flight continue using the old configuration. This guarantees each request sees a consistent configuration throughout its lifetime.
Validation¶
If your update contains invalid values, the server returns 422 with a validation error and the configuration is unchanged:
{
"error": {
"type": "validation_error",
"message": "1 validation error for ErrorInjectionConfig\nrate_limit_pct\n Input should be less than or equal to 100 [type=less_than_equal, ...]"
}
}
Related Pages¶
- Presets -- Pre-built configuration profiles
- ChaosLLM -- LLM-specific error types and endpoints
- ChaosWeb -- Web-specific error types and endpoints
- ChaosBlob -- Blob-specific error types and endpoints
- ChaosSMTP -- SMTP-specific listener, capture, and error injection behavior
- Metrics -- Metrics storage configuration