This error occurs when Docker cannot parse daemon.json due to incorrect JSON data types, such as using quoted strings for boolean or numeric values. Fix it by ensuring proper JSON syntax with correct data types in your configuration file.
When Docker starts, it attempts to load and parse the daemon configuration file (`/etc/docker/daemon.json` on Linux, `C:\ProgramData\docker\config\daemon.json` on Windows). The "json: cannot unmarshal" error specifically indicates a type mismatch problem - Docker is expecting one data type but finding another. The term "unmarshal" comes from Go (the language Docker is written in) and refers to the process of converting JSON text into Go data structures. When the JSON contains a value of the wrong type - for example, a string `"false"` where a boolean `false` is expected - the unmarshaling fails. This is different from a general JSON syntax error (like missing commas or brackets). The JSON itself is valid, but the values don't match what Docker expects for specific configuration options. Common examples include: - Using `"iptables": "false"` instead of `"iptables": false` - Using `"max-concurrent-downloads": "3"` instead of `"max-concurrent-downloads": 3` - Providing an object where Docker expects an array, or vice versa Docker will refuse to start until you fix the configuration, leaving all container operations unavailable.
First, get the full error message to identify which configuration key has the wrong type:
On Linux (systemd):
sudo journalctl -u docker.service -n 50 --no-pagerOr check service status:
sudo systemctl status docker.service -lLook for error patterns like:
- cannot unmarshal string into Go value of type bool - You used "true"/"false" as strings
- cannot unmarshal string into Go value of type int - You quoted a number
- cannot unmarshal object into Go value of type []string - You used an object where an array was expected
- cannot unmarshal array into Go value of type string - You used an array where a single string was expected
The error message will typically include the field name that has the wrong type.
The most common cause is quoting boolean values. Boolean values in JSON must NOT be quoted.
WRONG - strings instead of booleans:
{
"iptables": "false",
"debug": "true",
"live-restore": "true",
"userland-proxy": "false"
}CORRECT - actual boolean values:
{
"iptables": false,
"debug": true,
"live-restore": true,
"userland-proxy": false
}Common boolean options in daemon.json:
- debug
- tls
- tlsverify
- iptables
- ip-forward
- ip-masq
- ipv6
- userland-proxy
- live-restore
- experimental
- selinux-enabled
Numeric configuration values must also be unquoted.
WRONG - numbers as strings:
{
"max-concurrent-downloads": "3",
"max-concurrent-uploads": "5",
"max-download-attempts": "5",
"shutdown-timeout": "15"
}CORRECT - actual numbers:
{
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"max-download-attempts": 5,
"shutdown-timeout": 15
}Common numeric options:
- max-concurrent-downloads
- max-concurrent-uploads
- max-download-attempts
- shutdown-timeout
- default-shm-size (when specified as bytes, not string like "64M")
Proxy configuration requires a specific nested structure. The most common mistake is missing the intermediate default key.
WRONG - proxies directly under config:
{
"proxies": {
"httpProxy": "http://proxy.example.com:3128",
"httpsProxy": "http://proxy.example.com:3128",
"noProxy": "localhost,127.0.0.1"
}
}CORRECT - proxies nested under default (Docker 23.0+):
{
"proxies": {
"default": {
"httpProxy": "http://proxy.example.com:3128",
"httpsProxy": "http://proxy.example.com:3128",
"noProxy": "localhost,127.0.0.1"
}
}
}CORRECT - new format (Docker Engine 23.0+):
{
"proxies": {
"http-proxy": "http://proxy.example.com:3128",
"https-proxy": "http://proxy.example.com:3128",
"no-proxy": "localhost,127.0.0.1"
}
}Check your Docker version to determine which format to use:
docker --versionOptions inside log-opts and storage-opts should generally be strings, but some common mistakes occur:
CORRECT log-opts format (values are strings):
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3",
"labels": "production_status",
"env": "os,customer"
}
}WRONG - max-file as number:
{
"log-opts": {
"max-size": "10m",
"max-file": 3
}
}For log-opts, values should typically be strings since they're passed to the logging driver as key-value pairs.
Storage options are also strings:
{
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}Note that storage-opts is an array of strings, not an object.
Some configuration options expect arrays, others expect objects. Using the wrong structure causes unmarshal errors.
Options that expect ARRAYS:
{
"dns": ["8.8.8.8", "8.8.4.4"],
"dns-search": ["example.com"],
"dns-opts": ["ndots:5"],
"storage-opts": ["overlay2.override_kernel_check=true"],
"insecure-registries": ["myregistry.local:5000"],
"registry-mirrors": ["https://mirror.gcr.io"]
}Options that expect OBJECTS:
{
"log-opts": {
"max-size": "10m"
},
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime"
}
},
"default-address-pools": [
{"base": "172.80.0.0/16", "size": 24}
]
}Note that default-address-pools is an array of objects, each with base and size keys.
Before restarting Docker, validate your configuration file:
View the current file:
sudo cat /etc/docker/daemon.jsonValidate JSON syntax with jq:
sudo cat /etc/docker/daemon.json | jq .If the JSON is valid, jq will pretty-print it. If invalid, it shows the error.
Check the file location for your setup:
- Standard Linux install: /etc/docker/daemon.json
- Docker in snap (Ubuntu): /var/snap/docker/current/config/daemon.json
- Windows: C:\ProgramData\docker\config\daemon.json
- macOS Docker Desktop: ~/.docker/daemon.json
Create a fresh, minimal config if needed:
sudo tee /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOFAfter fixing the configuration, restart Docker and verify it's working:
Restart the Docker daemon:
sudo systemctl restart dockerCheck the service status:
sudo systemctl status dockerYou should see "active (running)" status.
Verify Docker is working:
docker ps
docker infoVerify your configuration was applied:
docker info | grep -A5 "Logging Driver"
docker info | grep "Storage Driver"The output should reflect your daemon.json settings.
### Complete daemon.json Type Reference
Here's a reference of correct data types for common daemon.json options:
Boolean options (no quotes around true/false):
{
"debug": true,
"tls": false,
"tlsverify": true,
"iptables": true,
"ip-forward": true,
"ip-masq": true,
"ipv6": false,
"userland-proxy": true,
"live-restore": true,
"experimental": false,
"selinux-enabled": false,
"no-new-privileges": false
}Integer options (no quotes around numbers):
{
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"max-download-attempts": 5,
"shutdown-timeout": 15,
"mtu": 1500,
"default-shm-size": 67108864
}String options:
{
"storage-driver": "overlay2",
"log-driver": "json-file",
"data-root": "/var/lib/docker",
"exec-root": "/var/run/docker",
"pidfile": "/var/run/docker.pid",
"group": "docker",
"default-runtime": "runc",
"containerd": "/run/containerd/containerd.sock",
"cgroup-parent": "",
"default-cgroupns-mode": "private",
"seccomp-profile": ""
}Array of strings options:
{
"dns": ["8.8.8.8", "8.8.4.4"],
"dns-search": ["example.com"],
"dns-opts": ["ndots:5"],
"insecure-registries": ["registry.local:5000"],
"registry-mirrors": ["https://mirror.example.com"],
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"],
"labels": ["environment=production", "region=us-east"],
"storage-opts": ["overlay2.override_kernel_check=true"],
"default-ulimits": []
}### Using Docker's Built-in Validator
Docker 18.09+ includes a configuration validator:
dockerd --validate --config-file /etc/docker/daemon.jsonThis checks the configuration without starting the daemon, helping you catch type errors before restarting.
### Debugging Unmarshaling Errors
If the error message is unclear, you can trace through the configuration:
1. Start with an empty config: {}
2. Add options one at a time
3. Restart Docker after each addition to identify the problematic option
### Version-Specific Differences
Configuration format has changed between Docker versions:
- Docker 17.x and earlier: Some options used different names
- Docker 18.09+: Added --validate flag
- Docker 20.10+: Changed proxy configuration format
- Docker 23.0+: New proxy configuration with http-proxy, https-proxy, no-proxy keys directly under proxies
Check the documentation for your specific Docker version:
docker --version### Common Pitfalls When Copying from Documentation
When copying configuration from web pages or documentation:
1. Some examples use comments (//) which are not valid in JSON
2. Trailing commas after the last item cause errors
3. Smart quotes (curly quotes) from word processors cause errors
4. Non-breaking spaces or other invisible characters cause issues
Always use a plain text editor and validate with jq before applying.
unable to configure the Docker daemon with file /etc/docker/daemon.json
How to fix 'unable to configure the Docker daemon with file daemon.json' in Docker
docker: Error response from daemon: OCI runtime create failed: container_linux.go: starting container process caused: exec: "/docker-entrypoint.sh": stat /docker-entrypoint.sh: no such file or directory
How to fix 'exec: entrypoint.sh: no such file or directory' in Docker
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
dockerfile parse error line 5: unknown instruction: RRUN
How to fix 'unknown instruction' Dockerfile parse error in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker