How to fix Error response from daemon: invalid character '<' looking for beginning of value in Docker

DockerINTERMEDIATEMEDIUMUpdated Dec 6, 2025· 221 views

This error occurs when Docker receives an HTML response instead of the expected JSON from a registry. Common causes include network proxies intercepting requests, corporate firewalls, geographic IP blocking, or misconfigured registry URLs.

Quick fix

Fixes Error response from daemon: invalid character '<' looking for beginning of value

# Test Docker Hub registry
curl -v https://registry-1.docker.io/v2/

# Test GitHub Container Registry
curl -v https://ghcr.io/v2/

# Test a private registry
curl -v https://your-registry.example.com/v2/
  1. Diagnose what is returning the HTML response
  2. Check and configure proxy settings
  3. Verify the registry URL is correct
  4. Re-authenticate with the registry
docker — error
# Test Docker Hub registry
curl -v https://registry-1.docker.io/v2/
# Test GitHub Container Registry
curl -v https://ghcr.io/v2/
# Test a private registry
curl -v https://your-registry.example.com/v2/
Error response from daemon: invalid character '<' looking for beginning of value

What this error means

This error indicates that Docker expected to receive a JSON response from a container registry but instead received an HTML page. When Docker communicates with registries (like Docker Hub, GitHub Container Registry, or private registries), it expects JSON-formatted responses containing image metadata and manifests. The key symptom is the `invalid character '<'` message - this `<` character is the start of an HTML document (like `<!DOCTYPE html>` or `<html>`). Docker's JSON parser encounters this HTML and fails because HTML is not valid JSON. This typically happens when something intercepts the request before it reaches the actual registry API. Instead of the registry responding, an intermediary returns an HTML page - often an error page (403 Forbidden, 404 Not Found), a captive portal login page, or a proxy authentication page. Docker cannot interpret this HTML response, hence the parsing error. The error commonly appears in these variations: - `error parsing HTTP 403 response body: invalid character '<' looking for beginning of value` - `error parsing HTTP 404 response body: invalid character '<' looking for beginning of value` - `Error response from daemon: invalid character '<' looking for beginning of value` - `error unmarshalling content: invalid character '<' looking for beginning of value`

Typical symptoms

  • Docker pull commands fail with 'invalid character' error
  • Docker push fails when trying to upload images to a registry
  • Docker login succeeds but subsequent operations fail
  • Error occurs intermittently or only on certain networks
  • CI/CD pipelines fail at container image pull/push steps
  • Error mentions HTTP status codes like 403, 404, or 401 alongside the parsing error
  • Works fine on home network but fails on corporate network
  • Docker commands work with VPN enabled but fail without it

Common causes

  1. Corporate proxy or firewall intercepting Docker registry traffic and returning an HTML error/block page
  2. Geographic IP blocking - Docker Hub blocks IPs from Cuba, Iran, North Korea, Crimea, Sudan, and Syria
  3. Captive portal (hotel/airport WiFi) requiring login before allowing internet access
  4. Typo in registry URL causing a 404 HTML response (e.g., 'gchr.io' instead of 'ghcr.io')
  5. SSL/TLS inspection by corporate firewall causing certificate issues
  6. Reverse proxy misconfiguration in front of a private registry
  7. Incorrect or stale credentials in ~/.docker/config.json
  8. Using deprecated registry URLs (e.g., docker.pkg.github.com instead of ghcr.io)
  9. Registry server returning HTML error pages instead of JSON API responses
  10. BuildKit compatibility issues with certain registry configurations

How to fix "Error response from daemon: invalid character '<' looking for beginning of value"

1Diagnose what is returning the HTML response

The first step is to identify what's actually responding to Docker's requests. Use curl to test the registry endpoint directly:

bash
# Test Docker Hub registry
curl -v https://registry-1.docker.io/v2/

# Test GitHub Container Registry
curl -v https://ghcr.io/v2/

# Test a private registry
curl -v https://your-registry.example.com/v2/

If you see HTML in the response (look for <!DOCTYPE or <html>), that confirms something is intercepting the request. A healthy registry returns JSON like:

json
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required"}]}

Note what you receive - is it a corporate firewall block page, a proxy authentication page, or a 404 error page?

2Check and configure proxy settings

If you're behind a corporate proxy, Docker needs to be configured to use it:

bash
# Create Docker service override directory
sudo mkdir -p /etc/systemd/system/docker.service.d

# Create proxy configuration file
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf << EOF
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:8080"
Environment="HTTPS_PROXY=http://proxy.example.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,*.internal.company.com"
EOF

# Reload and restart Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

# Verify proxy settings are applied
docker info | grep -i proxy

For Docker Desktop on Windows/Mac, configure proxy settings in:
- Docker Desktop > Settings > Resources > Proxies

Make sure to add any internal registries to NO_PROXY to bypass the proxy for internal traffic.

3Verify the registry URL is correct

A simple typo in the registry URL can cause this error. Double-check your image references:

bash
# Common typos that cause this error:
# Wrong: gchr.io (missing 'h')
# Right: ghcr.io

# Wrong: docker.pkg.github.com (deprecated)
# Right: ghcr.io

# Verify you can reach the correct registry
docker pull ghcr.io/owner/image:tag

# For Docker Hub images, the full path is:
docker pull docker.io/library/nginx:latest
# Or simply:
docker pull nginx:latest

If using a private registry, verify the hostname is correct and resolves properly:

bash
nslookup your-registry.example.com
ping your-registry.example.com
4Re-authenticate with the registry

Stale or corrupted credentials can cause authentication failures that result in HTML error pages:

bash
# Log out from all registries
docker logout
docker logout ghcr.io
docker logout your-registry.example.com

# Log back in to Docker Hub
docker login

# Log in to GitHub Container Registry
echo $GITHUB_PAT | docker login ghcr.io -u USERNAME --password-stdin

# Log in to a private registry
docker login your-registry.example.com

Also check your Docker config file for stale entries:

bash
# View current auth configuration
cat ~/.docker/config.json

# If you see corrupted or old entries, you can remove them:
# Edit ~/.docker/config.json and remove problematic auth entries
5Check for geographic IP blocking

Docker Hub blocks access from certain countries due to US export control regulations. If you're in Cuba, Iran, North Korea, Crimea, Sudan, or Syria, you'll receive a 403 response.

To verify if this is the issue:

bash
# Check your public IP
curl ifconfig.me

# Test with a VPN from an allowed region
# Enable VPN, then:
docker pull nginx:latest

Workarounds:
1. Use a VPN service
2. Use a Docker registry mirror (if available in your region)
3. Set up a private registry and manually transfer images

6Handle captive portals and network authentication

If you're on a network with a captive portal (hotel WiFi, airport, conference center), you need to authenticate through it first:

1. Open a web browser and try to visit any HTTP site (not HTTPS)
2. The captive portal should redirect you to a login page
3. Complete the authentication
4. Retry Docker commands

To check if a captive portal is the issue:

bash
# Try to access a plain HTTP site
curl -v http://example.com

# If you see a redirect to a login page in the response,
# you have a captive portal issue

After authenticating, verify connectivity:

bash
curl -v https://registry-1.docker.io/v2/
7Fix SSL certificate issues for private registries

If using a private registry with self-signed or corporate CA certificates:

bash
# Create certificate directory for the registry
sudo mkdir -p /etc/docker/certs.d/your-registry.example.com:5000

# Copy the CA certificate
sudo cp ca.crt /etc/docker/certs.d/your-registry.example.com:5000/

# If using client certificates, also copy:
sudo cp client.cert /etc/docker/certs.d/your-registry.example.com:5000/
sudo cp client.key /etc/docker/certs.d/your-registry.example.com:5000/

# Restart Docker
sudo systemctl restart docker

Alternatively, for testing only (not recommended for production), you can add the registry as insecure:

bash
# Edit /etc/docker/daemon.json
{
  "insecure-registries": ["your-registry.example.com:5000"]
}

# Restart Docker
sudo systemctl restart docker
8Try disabling BuildKit temporarily

In some cases, BuildKit can have compatibility issues with certain registries:

bash
# Disable BuildKit for a single build
DOCKER_BUILDKIT=0 docker build -t myimage .

# Or disable BuildKit globally in daemon.json
# Edit /etc/docker/daemon.json:
{
  "features": {
    "buildkit": false
  }
}

# Restart Docker
sudo systemctl restart docker

If disabling BuildKit resolves the issue, consider:
1. Updating Docker to the latest version
2. Checking if your registry supports BuildKit's manifest format
3. Opening an issue with the registry maintainers

9Contact your IT department or use alternative networks

If the issue is caused by corporate network policies:

1. Request whitelist: Ask IT to whitelist Docker registry domains:
- registry-1.docker.io
- auth.docker.io
- production.cloudflare.docker.com
- ghcr.io
- *.pkg.github.com

2. Request SSL inspection bypass: If your company uses SSL inspection, request that Docker registry traffic be exempted

3. Use a different network: As a temporary workaround, use a personal mobile hotspot or different network

4. Set up an internal registry mirror: Have IT set up an internal Docker registry that mirrors needed images:

bash
# Configure Docker to use internal mirror
# Edit /etc/docker/daemon.json:
{
  "registry-mirrors": ["https://internal-mirror.company.com"]
}

Advanced notes

### Understanding the Error in Detail

When Docker communicates with a registry, it uses the Docker Registry HTTP API V2. All responses should be JSON-formatted. The error occurs in Docker's Go JSON unmarshaller when it encounters unexpected characters.

The specific error invalid character '<' looking for beginning of value means:
- Docker tried to parse a JSON response
- The first character was < instead of {, [, ", or a JSON primitive
- This < is typically the start of <!DOCTYPE html> or <html>

### Debugging with Verbose Output

Enable verbose/debug output to see exactly what's happening:

bash
# Enable Docker CLI debug mode
export DOCKER_CLI_DEBUG=1
docker pull nginx:latest

# Or check Docker daemon logs
sudo journalctl -u docker.service -f

# On Docker Desktop, enable debug mode in settings
# Then view logs at:
# macOS: ~/Library/Containers/com.docker.docker/Data/log/
# Windows: %LOCALAPPDATA%\Docker\log\

### Common HTTP Status Codes with This Error

- 403 Forbidden: Usually indicates firewall blocking or geographic restrictions
- 404 Not Found: Registry URL typo or image doesn't exist
- 401 Unauthorized: Authentication required but credentials missing or invalid
- 407 Proxy Authentication Required: Corporate proxy needs credentials

### Registry API Testing

To fully test registry connectivity without Docker:

bash
# Get auth token for Docker Hub
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/nginx:pull" | jq -r .token)

# Test manifest fetch
curl -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  https://registry-1.docker.io/v2/library/nginx/manifests/latest

# If this returns JSON, Docker should work
# If this returns HTML, something is intercepting the request

### For Private Registry Operators

If you're operating a registry and users report this error:

1. Check reverse proxy configuration: Ensure error pages return JSON, not HTML
2. Configure proper error responses: The registry should return JSON even for errors
3. Review authentication flow: Auth failures should return JSON error responses
4. Check registry logs: Look for what's actually being returned to clients

Example nginx configuration for a registry:

nginx
location /v2/ {
    proxy_pass http://registry:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;

    # Return JSON errors, not HTML
    error_page 502 503 504 =503 @json_error;
}

location @json_error {
    default_type application/json;
    return 503 '{"errors":[{"code":"UNAVAILABLE","message":"Service temporarily unavailable"}]}';
}

Frequently asked questions

What does "Error response from daemon: invalid character '<' looking for beginnin" mean?
This error indicates that Docker expected to receive a JSON response from a container registry but instead received an HTML page. When Docker communicates with registries (like Docker Hub, GitHub Container Registry, or private registries), it expects JSON-formatted responses containing image metadata and manifests. DOCTYPE html> or <html>).
How do I fix "Error response from daemon: invalid character '<' looking for beginnin"?
This error occurs when Docker receives an HTML response instead of the expected JSON from a registry. Common causes include network proxies intercepting requests, corporate firewalls, geographic IP blocking, or misconfigured registry URLs.
What causes "Error response from daemon: invalid character '<' looking for beginnin"?
Corporate proxy or firewall intercepting Docker registry traffic and returning an HTML error/block page Geographic IP blocking - Docker Hub blocks IPs from Cuba, Iran, North Korea, Crimea, Sudan, and Syria Captive portal (hotel/airport WiFi) requiring login before allowing internet access
Is the "Error response from daemon: invalid character '<' looking for beginnin" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading