How to Fix Docker daemon.json Parse Error: Invalid Character Crashing the Docker Daemon
Threat/Impact Level: CRITICAL | Exploitability/Downtime Risk: HIGH | Time to Fix: 5 mins
TL;DR
- What broke:
dockerdfailed to start because/etc/docker/daemon.jsoncontains an invalid character — trailing comma, single quote, unquoted key, or a UTF-8 BOM — making the entire JSON unparseable. - How to fix it: Run
dockerd --validateorpython3 -m json.tool /etc/docker/daemon.jsonto pinpoint the offending line, then correct the syntax. - Fast path: Use our Client-Side Sandbox above to paste your
daemon.jsonand auto-refactor it instantly without sending your config anywhere.
The Incident (What Does the Error Mean?)
The raw error from journalctl -u docker.service or systemctl status docker looks like this:
failed to load daemon configuration file: /etc/docker/daemon.json:
invalid character '}' looking for beginning of object key string
or
failed to load daemon configuration file: /etc/docker/daemon.json:
invalid character '\'' looking for beginning of value
Immediate consequence: dockerd refuses to start. Every container on the host — including sidecars, monitoring agents, and any service depending on the Docker socket — is dead. On a Swarm manager node or a CI runner host, this is a full outage. There is no graceful degradation; the daemon either parses the config cleanly or it does not start at all.
The Attack Vector / Blast Radius
This is not a security exploit, but the blast radius on a production host is severe:
- Single host: All running containers are orphaned.
docker psreturnsCannot connect to the Docker daemon. - Swarm node: A manager going down mid-deployment can leave the cluster in a split-brain scheduling state.
- CI/CD runners: Every pipeline job on the affected runner fails immediately. Depending on your runner pool size, this can stall your entire deployment pipeline.
- Kubernetes (Docker shim or containerd fallback misconfigured): If you edited
daemon.jsonto configureinsecure-registriesorlog-driverfor a node, that node's kubelet loses its container runtime and the node goesNotReady, triggering pod evictions across the cluster.
The most common causes in order of frequency:
- Trailing comma after the last key-value pair (the #1 offender — copy-pasted from JavaScript-tolerant editors)
- Single quotes instead of double quotes
- Unquoted string values
- UTF-8 BOM injected by Windows editors (Notepad, some VS Code configs) when the file is transferred to Linux
- Comments (
//or#) — JSON does not support comments
How to Fix It
Step 0: Validate Before Editing
# Pinpoint the exact line and character offset
python3 -m json.tool /etc/docker/daemon.json
# Or use jq
jq . /etc/docker/daemon.json
# Docker's own validator (Docker 23.0+)
dockerd --validate --config-file /etc/docker/daemon.json
Basic Fix: Trailing Comma (Most Common)
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
- },
- "insecure-registries": ["registry.internal:5000"],
+ },
+ "insecure-registries": ["registry.internal:5000"]
}
Basic Fix: Single Quotes
{
- 'log-driver': 'json-file',
- 'storage-driver': 'overlay2'
+ "log-driver": "json-file",
+ "storage-driver": "overlay2"
}
Basic Fix: Stripping a UTF-8 BOM
If file /etc/docker/daemon.json returns UTF-8 Unicode (with BOM), the invisible \xEF\xBB\xBF prefix at byte 0 is your invalid character.
# Strip BOM in-place
sed -i '1s/^\xef\xbb\xbf//' /etc/docker/daemon.json
# Verify
file /etc/docker/daemon.json
# Expected: /etc/docker/daemon.json: ASCII text
Enterprise Best Practice: Managed daemon.json via Configuration Management
Stop editing daemon.json by hand on live hosts. Manage it through Ansible, Chef, or Puppet with a schema-validated template.
Ansible task with pre-flight validation:
- name: Copy daemon.json directly
- copy:
- src: files/daemon.json
- dest: /etc/docker/daemon.json
+ name: Validate daemon.json locally before deploying
+ delegate_to: localhost
+ command: python3 -m json.tool {{ role_path }}/files/daemon.json
+ changed_when: false
+
+ name: Deploy validated daemon.json
+ copy:
+ src: files/daemon.json
+ dest: /etc/docker/daemon.json
+ owner: root
+ group: root
+ mode: '0644'
+ notify: restart docker
Canonical, production-safe daemon.json structure:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "5"
},
"storage-driver": "overlay2",
"insecure-registries": [],
"live-restore": true,
"userland-proxy": false,
"metrics-addr": "127.0.0.1:9323"
}
Note:
live-restore: trueis the single most important production setting — it keeps containers running during a daemon restart, giving you a window to fix config errors without a full outage.
💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.
Prevention in CI/CD
1. Pre-commit Hook (fastest feedback loop)
# .git/hooks/pre-commit
if git diff --cached --name-only | grep -q 'daemon.json'; then
python3 -m json.tool /etc/docker/daemon.json > /dev/null || {
echo "ERROR: daemon.json is invalid JSON. Commit blocked."
exit 1
}
fi
2. Checkov IaC Scan
If your daemon.json is rendered from a Terraform templatefile() or a Helm values file:
checkov -f daemon.json --framework json
3. GitHub Actions Validation Step
- name: Validate Docker daemon config
run: |
jq empty ansible/roles/docker/files/daemon.json
echo "daemon.json is valid JSON"
4. OPA Policy (Conftest) for Structural Rules
Enforce that live-restore is always true and insecure-registries is never populated in production:
package docker.daemon
deny[msg] {
input["live-restore"] != true
msg := "live-restore must be true in production daemon.json"
}
deny[msg] {
count(input["insecure-registries"]) > 0
msg := "insecure-registries must be empty in production"
}
conftest test daemon.json --policy docker-policy/
This catches both syntax errors (conftest will refuse to parse invalid JSON) and semantic misconfigurations before any file touches a production host.