Skip to content
Control Plane Labs

530 Unable to Resolve Origin Hostname

Server error response defined by developers.cloudflare.com.

Last updated July 27, 2026

Common causes at a glance

  • A proxied CNAME pointing at a hostname that does not resolve
  • A CNAME target whose own DNS has expired or been deleted
  • A dangling record left behind after a platform migration
  • An Origin Rule or Worker route naming a hostname with no DNS answer

Reproduce it

curl -s https://www.example.com/ | grep -oE 'Error 1[0-9]{3}'

What 530 Unable to Resolve Origin Hostname means

530 is a wrapper. Cloudflare needed an HTTP status for the wire, picked an unused one, and wrote the real diagnosis into the page. Reading the 530 alone tells you almost nothing; reading the 1xxx code inside it tells you everything. The usual companion is Error 1016, origin DNS error, meaning the hostname a proxied record points to did not resolve.

That makes 530 unlike the rest of the family. Every other code here describes a failure between the edge and a known origin address. 530 means the edge never got as far as having an address.

Where it comes from

530 is not in the IANA HTTP Status Code Registry and has no RFC behind it. Cloudflare documents it on its 5xx error page, which mostly redirects to the 1xxx error index. RFC 9110 §15 requires clients to treat an unrecognised 5xx as 500, which is unusually destructive here: the detail was in the body, not the status line, so collapsing 530 to 500 discards the only useful part. As with every code here the page comes from Cloudflare’s edge, and your origin logs will be empty because the edge could not work out where the origin lives.

What actually causes it

Every one of these reduces to the same thing: a record in Cloudflare’s DNS points at a name with no answer behind it. Platform migrations are the usual source. A CNAME to a Heroku app, an S3 bucket, or a load balancer outlives the resource it named, and the record sits there resolving to nothing. Expired domains do the same at one remove. This stays confusing because the visitor sees an error attributed to your site while the broken name belongs to a third party you stopped using months ago.

How to debug it

Read the 1xxx code first. Everything else is guesswork until you have it, and it is in the body of the error page:

curl -s https://www.example.com/ | grep -oE 'Error 1[0-9]{3}'

For the usual answer, 1016, walk the record chain and find the link returning nothing. Follow each CNAME to its target and query that target directly; the failure is at whichever hop returns NXDOMAIN or an empty answer. The DNS tool does this faster than three rounds of dig. Then repoint the record or delete it.

Do not bother bypassing the edge with curl --resolve here. Unlike the other codes in this family there is no origin IP to bypass to, which is the entire problem. The status code reference covers what a neighbouring code would have meant.

Working examples

curl

# Step 1: extract the 1xxx code. The 530 itself is not the error.
curl -s https://www.example.com/ | grep -oE 'Error 1[0-9]{3}'

# Step 2: walk the CNAME chain and find the hop with no answer.
dig +short CNAME www.example.com
dig +short A app-name.herokudns.com

# Empty output from the target is your 1016.

Python (requests)

import re, requests, dns.resolver

resp = requests.get("https://www.example.com/", timeout=10)
print(resp.status_code)  # 530

# The useful part is in the body, not the status line.
match = re.search(r"Error (1\d{3})", resp.text)
print("cloudflare code:", match.group(1) if match else "not found")

# For 1016, find which hop in the chain resolves to nothing.
try:
    target = dns.resolver.resolve("www.example.com", "CNAME")[0].target
    print("cname ->", target)
    print("resolves to:", dns.resolver.resolve(target, "A"))
except dns.resolver.NXDOMAIN:
    print("dead CNAME target — this is your 1016")

Node (fetch)

import { promises as dns } from "node:dns";

const res = await fetch("https://www.example.com/");
const body = await res.text();
console.log(res.status, body.match(/Error (1\d{3})/)?.[1]);

// Chase the CNAME target; the broken hop is the one that throws.
try {
  const [target] = await dns.resolveCname("www.example.com");
  console.log("cname ->", target);
  console.log("a ->", await dns.resolve4(target));
} catch (e) {
  console.log("chain broken at:", e.hostname, e.code); // ENOTFOUND -> 1016
}

Reference and tooling

The authoritative list of assigned status codes is theIANA HTTP Status Code Registry. For a searchable copy with the semantics summarised, use theHTTP status code reference on this site. To see exactly what a server is sending, theheader inspector shows the raw status line and response headers, and thecurl builder assembles the request flags for you.

Other 5xx codes