| name | configs |
| description | Use for configuration repair and validation tasks involving YAML, JSON, TOML, environment variables, Nginx, Docker Compose, Kubernetes manifests, feature flags, service settings, logging, rate limits, and runtime behavior controlled by config files. |
Configuration Repair Field Guide
Configuration bugs share a single signature: the file parses cleanly but the
service does the wrong thing. Syntactic validity is cheap; semantic
correctness is the work.
Three questions before any edit:
- Which file does the runtime actually read? Sources may be templated, layered, or environment-overridden.
- Which component consumes it? Parser version + supported field surface.
- What does "working" look like? A smoke command, a probe, an assertion against the live config.
The rest is per-format.
YAML
safe_load always — yaml.load allows arbitrary code execution and is never
the right call for untrusted input.
import yaml
with open("config.yaml") as f:
data = yaml.safe_load(f) or {}
data["settings"]["timeout"] = 20
with open("config.yaml", "w") as f:
yaml.safe_dump(data, f, default_flow_style=False, sort_keys=False)
Useful dump options:
default_flow_style=False — block style, human-readable
sort_keys=False — preserve original key order (load-bearing for tests and humans)
allow_unicode=True — non-ASCII without escapes
Error-tolerant load when the file may be missing or partial:
def load_config(path, defaults):
try:
with open(path) as f:
loaded = yaml.safe_load(f) or {}
except FileNotFoundError:
return defaults
except yaml.YAMLError as e:
raise RuntimeError(f"YAML parse error in {path}: {e}")
return {**defaults, **loaded}
YAML traps:
- Indentation is significant. Mixed tabs/spaces fail downstream even when the parser accepts.
- Anchors (
&name) and aliases (*name) load correctly but safe_dump flattens them — verify if downstream consumers depend on shared identity.
- A bare
null and an empty string are different. Tests can pass on one and fail on the other.
- Quote ambiguous scalars:
"yes", "no", "on", "off", version strings ("1.10"), country codes ("NO").
Docker Compose
Check this list, in order:
- Services: every name unique;
depends_on targets exist.
- Ports:
host:container. Mapping a port the host already binds breaks startup.
- Volumes: bind mounts (
./path:/in/container) vs named volumes; named volumes need top-level volumes: declaration.
- Environment: distinguish
${VAR} (resolved at compose time) from runtime env in the container.
- Healthchecks: command must exist inside the image (
curl is not in alpine). interval, timeout, retries must accommodate slow startup.
- depends_on:
condition: service_healthy requires a healthcheck on the dep. Without condition, depends_on only sequences startup, not readiness.
docker compose config parses + resolves and prints the merged config.
Kubernetes manifests
Every selector/label pair is a load-bearing string. The most common silent
bug: a Service selector does not match Pod labels, so the Service has
zero endpoints and traffic times out without any visible error.
Checklist:
- Service
spec.selector ↔ Pod metadata.labels.
- Service
targetPort ↔ container containerPort.
- ConfigMap/Secret references: name + key both exist.
- Probes:
readinessProbe, livenessProbe point to a port and path the container actually exposes.
- Resource requests/limits: pod cannot be scheduled if requests exceed cluster capacity.
kubectl apply --dry-run=server -f manifest.yaml validates server-side
schema. kubectl explain <kind>.<field> reveals the supported surface for
the cluster's API version.
Nginx and HTTP routing
server block selection: listen + server_name (longest, then exact, then wildcard).
location precedence: exact =, then ^~ prefix, then regex ~/~*, then prefix.
upstream: every name referenced in proxy_pass must be declared.
- Logging:
log_format defines fields; access_log references format name and target file.
- Rate limits:
limit_req_zone declares the zone in the http block; limit_req uses it in server/location.
nginx -t validates syntax. For semantic checks, render the resolved config
with nginx -T and grep the directives that should be there.
TOML
pyproject.toml, Cargo.toml, MinIO/HashiCorp runtime configs.
- Parse with
tomllib (3.11+) or tomli; write with tomli-w. Never regex if the file has arrays-of-tables.
- Keys with dots:
a.b.c = 1 flattens to nested mapping; [a.b]\nc = 1 is a nested table. Different shape, different test outcomes.
- Strings that look like commands or paths stay literal; do not expand
${VAR} unless the consumer documents that it does.
JSON
- Many tools write trailing newline. Some tests assert byte-equality — preserve.
- Use
indent=2 (or whatever the original used). Drift in indent style breaks reviews and sometimes diffs.
- Schema-driven configs (k8s, OpenAPI) — check the schema before editing fields you do not recognise.
Environment variables
.env files: many parsers do not support quoting or interpolation. KEY=value with spaces is risky.
printenv / process env at runtime is the truth. A var defined in compose environment: overrides one in env_file:.
- Boolean flags:
"true", "1", "yes" accepted differently per consumer. Match exact precedent in the codebase.
Pitfalls
- Editing the generated file rather than the source template — drift on next regenerate.
- Syntactically valid YAML with the wrong field name silently ignored — pin schemas, do not assume the parser warns.
depends_on without health condition mistaken for "wait until ready".
- Service selector divergence from Pod labels — Service has zero endpoints, no log line.
- Lost comments or key order in a human-maintained file without reason.
- Adding env vars to compose without rebuilding the image when the consumer reads them at build time.
- Trusting
nginx -t past syntax — semantic correctness still requires -T plus a request.