Blog / A 404 on robots.txt allows every crawler, a 503 blocks them all

A 404 on robots.txt allows every crawler, a 503 blocks them all

RFC 9309 gives a missing robots.txt and a broken robots.txt opposite meanings: a 4xx lets a crawler access any resource on the server, a 5xx obliges it to assume complete disallow. Google's documentation carves 429 out of that rule. Lantad's code does not.

In short

  • RFC 9309, the Robots Exclusion Protocol published on the Standards Track in September 2022, states that a robots.txt status in the 400 to 499 range means the crawler MAY access any resources on the server, and that a status in the 500 to 599 range means the crawler MUST assume complete disallow.
  • Google's robots.txt documentation describes a 5xx path the RFC does not: crawling stops for the first 12 hours, the last good robots.txt is used for the next 30 days, and after 30 days Google behaves as if there is no robots.txt file.
  • Google's documentation excludes 429 from its 4xx handling by name, while RFC 9309 puts 429 inside the 400 to 499 range that permits access to any resource, so the same status code has two published readings.
  • Lantad's robotsPolicyFromStatus in core/src/robots.ts has exactly three branches: a 2xx parses the file, a status of 500 or above selects assume_disallow, and every other status, 429 included, selects allow_all.
  • A robots.txt Lantad cannot fetch at all, from a network error or an exhausted request budget, is treated as allow_all rather than as the complete disallow RFC 9309 requires for unreachable files, and this post states that divergence rather than hiding it.

Two sites lose their robots.txt on the same morning. One returns 404, because somebody deleted the file during a deploy. The other returns 503, because the origin behind it is overloaded. Neither site has a rules file any more, and on a monitoring dashboard the two incidents look like the same kind of bad day.

To a crawler following the specification they are opposites. RFC 9309, the Robots Exclusion Protocol, published on the Standards Track in September 2022 by M. Koster, G. Illyes, H. Zeller and L. Sassman, says that a status code in the 400 to 499 range means the crawler may access any resources on the server, and that a status code in the 500 to 599 range means the crawler must assume complete disallow. Deleting the file opens everything to an AI crawler. Breaking the file closes everything. The absence of rules is not a neutral state, and which way it resolves comes down to a status code that almost nobody picked on purpose.

This post reads that part of the specification, then reads what Google documents its own crawlers doing, which is not the same thing, then reads what Lantad's scanner does, which is not quite the same as either. Every claim below comes from one of three places: the RFC, first party crawler documentation, or the core directory of this repository. Nothing here is a scan result. Lantad has not measured how often robots.txt returns a server error in the wild, and this post does not imply that it has.

  • Successful access (2xx) Follow the rules Section 2.3.1.1. The crawler MUST follow the parseable rules in the file it downloaded.
  • Redirects (3xx) Follow up to five hops Section 2.3.1.2. At least five consecutive redirects SHOULD be followed, even across authorities. Beyond five, the crawler MAY assume the file is unavailable.
  • Unavailable (4xx) Crawl anything Section 2.3.1.3. The crawler MAY access any resources on the server. A deleted robots.txt permits everything.
  • Unreachable (5xx or network error) Assume complete disallow Section 2.3.1.4. The file is undefined and the crawler MUST assume complete disallow. The strongest requirement level in the document.
The four access results RFC 9309 names in section 2.3.1, and what each obliges a conforming crawler to do. Read from the specification, not measured.

Why a missing robots.txt and a broken robots.txt mean opposite things

Section 2.3.1 of the protocol splits the outcome of a robots.txt fetch into four named cases: successful access, redirects, unavailable status, and unreachable status. The two that decide this question are the last two, because they are the two that leave the crawler holding no rules at all.

Unavailable is section 2.3.1.3. It defines the case as the crawler trying to fetch the file and the server responding with status codes indicating that the resource in question is unavailable, and it gives the 400 to 499 range as the HTTP example. The consequence is one sentence long: if a server status code indicates that the robots.txt file is unavailable to the crawler, then the crawler may access any resources on the server. A 404 is therefore not the absence of an instruction. It is an instruction, and the instruction is yes.

Unreachable is section 2.3.1.4, and it runs the other way. If the robots.txt file is unreachable due to server or network errors, the document says, this means the robots.txt file is undefined and the crawler must assume complete disallow, with server errors identified as the 500 to 599 range. That is the strongest requirement level the document uses anywhere. Not should, not may. A crawler that carries on fetching your pages while your robots.txt returns 503 is not following the specification it says it follows.

There is a release valve, and knowing about it changes the shape of the problem from permanent to temporal. The same section continues: if the robots.txt file is undefined for a reasonably long period of time, for example 30 days, crawlers may assume that the robots.txt file is unavailable as defined in section 2.3.1.3, or continue to use a cached copy. So a 5xx that lasts an hour is a lockout, and a 5xx that lasts two months converges back on the 4xx behaviour. The dangerous window is the middle of that range: long enough to cost you every conforming crawler on the web, short enough that nothing has yet timed out into permissiveness.

Two consequences follow for anyone thinking about AI visibility rather than about classical search ranking. The first is that this is one of the very few controls in the stack that fails closed by design. Almost everything else that governs whether a machine can read your pages fails open: a missing structured data block, an absent llms.txt, a stylesheet that did not load. A 503 on one small text file is the exception, and it takes the whole origin with it. The second is that robots.txt sits at a different layer from the thing that actually returns status codes to crawlers, which is the argument in two layers decide whether AI can read your site. Your file can be flawless and your edge can still refuse the request. Your file can also be flawless and 503, at which point its flawlessness is irrelevant, because nothing parsed it. How the score works keeps those two as separate findings for exactly that reason.

Sample Illustrative, not a measurement of any real site.

GET /robots.txt returns 404

  • Status class: unavailable, section 2.3.1.3
  • Requirement: crawler MAY access any resources
  • Effect on the site: fully crawlable
  • Effect on a Disallow you meant to keep: gone

GET /robots.txt returns 503

  • Status class: unreachable, section 2.3.1.4
  • Requirement: crawler MUST assume complete disallow
  • Effect on the site: nothing may be fetched
  • Effect after roughly 30 days: MAY revert to the 4xx reading
The same absent rules, resolved two ways by RFC 9309 sections 2.3.1.3 and 2.3.1.4. Illustrative of the specified behaviour, not a capture of any real site.

Google documents a different 5xx path, and pulls 429 out of the 4xx rule

The specification says what a conforming crawler must do. It does not say what any particular crawler does, and the operator of the largest fleet publishes a description that departs from it in two places.

Google's robots.txt documentation sets out handling by status class. For 5xx it does not say complete disallow and stop. It says that for the first 12 hours Google stops crawling the site but keeps trying to fetch the robots.txt file, that if it cannot fetch a new version then for the next 30 days it will use the last good version while still trying to fetch a new one, and that if the errors are still not fixed after 30 days, and the site is generally available to Google, it will behave as if there is no robots.txt file.

Set that beside the RFC and it reads less like a contradiction than like a gap filled in. The specification permits a cached copy after a reasonably long period; Google names the period, names the copy, and names an intermediate state the RFC does not describe at all, which is half a day of not crawling followed by a fallback to your last good rules rather than to nothing. If your robots.txt broke this morning and its last working version disallowed a training crawler, that disallow is documented as still in force tomorrow. Complete disallow and last good version produce the same answer only when the last good version was itself restrictive, and for most sites it was not.

The second departure is a single status code, and it is the one worth writing on a card. Google's documentation states that its crawlers treat all 4xx errors, except 429, as if a valid robots.txt file did not exist. 429 is Too Many Requests: exactly the status a rate limiter or a bot defence returns when it decides a client is being greedy. Under the plain text of the RFC, 429 falls inside the 400 to 499 range, so it is unavailable, so the crawler may access any resource on the server. Under Google's documentation it is pulled out of that rule by name. The same three digits open the gates in one text and are explicitly withheld in the other.

That is not a hypothetical on this site. When we captured six real storefronts on 15 July 2026, allbirds.com answered our honestly identified crawler with HTTP 429 and produced no score at all, which is reported in what a crawler actually meets on a real storefront. That 429 was on the page request rather than on the robots.txt request, and the distinction is the whole point: a defence tuned to throw 429 at automated traffic has no particular reason to exempt one text file, and if it does not exempt it, the file that governs every crawler on the site starts returning a status that two primary documents read in opposite directions. The other vendors do not settle it. Read OpenAI's bots documentation and Anthropic's crawler article as they stood on 29 July 2026 and neither carries any statement about HTTP status codes or robots.txt fetch failures. Both tell you the tokens and how to block them. What happens when the file itself errors is undocumented in both directions, and if you find a page on either host that covers it, we will correct this post.

  • 404 on robots.txt Agreed: crawl anything RFC 9309 says unavailable, so the crawler MAY access any resource. Google says it behaves as if a valid file did not exist. Lantad selects allow_all.
  • 429 on robots.txt Disputed RFC 9309 puts it in the 400 to 499 range with no carve out. Google's documentation excludes 429 from that rule by name. Lantad selects allow_all.
  • 503 on robots.txt Agreed in direction, not in detail RFC 9309 says the crawler MUST assume complete disallow. Google documents 12 hours of no crawling, then 30 days on the last good copy. Lantad selects assume_disallow.
  • No response at all Disputed RFC 9309 names network errors as unreachable, so complete disallow. Lantad treats an unfetchable robots.txt as allow_all. Google's page does not address it.
How three texts read the same four status classes on a robots.txt fetch. RFC 9309 and Google's crawler documentation read on 29 July 2026; the Lantad column is read from core/src/robots.ts in this repository.

The four numbers RFC 9309 attaches to a robots.txt fetch

Most of the protocol is prose about grammar and matching. Four numbers in it constrain implementations, and all four are worth knowing because each one is a place where a crawler can legitimately behave differently from the one next to it while both remain conformant.

Five is the redirect budget. Section 2.3.1.2 says crawlers should follow at least five consecutive redirects, even across authorities, which in the HTTP case means across hosts. If the file is reached inside those five hops it must be fetched, parsed, and its rules followed in the context of the initial authority, so a robots.txt served from a CDN hostname still governs the original site rather than the CDN. Past five hops, crawlers may assume the file is unavailable, which routes straight back to the permissive branch. Google's documentation puts the same number differently: it follows at least five redirect hops and then stops and treats it as a 404 for the robots.txt file. A redirect loop on that path therefore ends in an open site, not a closed one.

Twenty four is the cache ceiling. Section 2.4 says crawlers may cache the file's contents, may use standard cache control as defined in RFC 9111, and should not use the cached version for more than 24 hours unless the file is unreachable. That last clause is the one people miss. It is the hook that makes Google's 30 day fallback conformant: once the file is unreachable, the 24 hour ceiling stops applying, and a crawler may hold your old rules for as long as it likes. It also means a robots.txt change you made this morning is not guaranteed to be in effect this afternoon.

Five hundred kibibytes is the parsing floor. Section 2.5 says crawlers should impose a parsing limit and that the limit must be at least 500 kibibytes. It is a floor on the crawler, not a cap on you, but the practical reading is the same either way: rules past roughly half a megabyte are outside what any crawler is obliged to read. Very few robots.txt files come close, and the ones that do usually got there by generating a Disallow line per URL, which is a different problem.

Thirty days is the amnesty, and it is the only one of the four expressed as an example rather than a requirement. The text reads for example 30 days, which leaves the reasonably long period undefined and lets each crawler pick. Google picked 30. Nothing obliges anyone else to. Put the four together and the honest summary is that the specification pins down direction far more tightly than timing: everyone agrees a 5xx closes the site and a 4xx opens it, and nobody has to agree on how long the closure lasts. That is a very different guarantee from the one people assume they have, and it is the same shape as the gap between what llms.txt promises and what crawlers do with it.

  • Redirect hops a crawler SHOULD follow, at least 5 Section 2.3.1.2. Beyond this the file MAY be treated as unavailable.
  • Hours a cached robots.txt SHOULD last, at most 24 Section 2.4, and the ceiling lifts entirely once the file is unreachable.
  • Days of an undefined file before the amnesty, by example 30 Section 2.3.1.4, written as an example rather than a requirement.
  • Kibibytes a crawler MUST parse, at least 500 Section 2.5. A floor on the crawler, not a cap on the publisher.
  • Kibibytes Lantad reads from robots.txt 512 The byte cap passed to the robots.txt capture in core/src/pipeline.ts.
The four numeric constraints RFC 9309 places on robots.txt handling, alongside the byte cap Lantad's own robots.txt fetch uses. Specification values read from RFC 9309; the 512 figure is read from core/src/pipeline.ts. Not a measurement of any site.

What Lantad's scanner does with each status, read from its own source

All of the status handling in this product lives in one exported function, robotsPolicyFromStatus in core/src/robots.ts, and it is short enough to describe completely. It takes a status and a body and returns one of three policies. A status from 200 to 299 returns kind parsed, with the file handed to the parser. A status of 500 or above returns kind assume_disallow, carrying a note that says robots.txt returned that status and that crawlers commonly treat a failing robots.txt as disallow-all until it recovers. Everything else returns kind allow_all, carrying a note that says per RFC 9309 an unavailable robots.txt imposes no restrictions.

Three branches, and the third one is a default rather than a case. That is where 429 lands. Google's documentation pulls 429 out of its 4xx handling; this code does not, because the branch is written as a range test and a fallthrough. Whether that is right is arguable in both directions. The RFC's plain text is on the side of the fallthrough. Google's documented behaviour is on the other side, and Google is the crawler most likely to be looking at your site. Naming it is the part that is not arguable, which is why it is in this post and in the takeaways rather than in a comment nobody reads.

The second divergence is larger and it is upstream of that function. When the robots.txt fetch fails outright, from a network error, a timeout, or the scan's own request budget running out, core/src/pipeline.ts never calls robotsPolicyFromStatus at all. It constructs an allow_all policy directly, with a note recording that the file could not be fetched and was treated as unrestricted. Section 2.3.1.4 names network errors alongside server errors as unreachable, so a conforming crawler must assume complete disallow there. Lantad assumes the opposite. The argument for it is that a scanner is not a crawler harvesting content, and that reporting a site as fully blocked because our own request timed out would be the confidently wrong grade this product exists not to emit, an instinct set out in why we withhold a grade. The argument against it is that the specification does not carve out scanners. Both are true. We have not changed the behaviour, and this post does not promise that we will.

What the code does get right is refusing to dress the assumption up as a rule. When the policy is assume_disallow, core/src/verdict.ts still applies the access deduction of 0.4 for each penalised purpose class, and the penalised classes are search and user_agent, so a failing robots.txt costs 0.8 of a sub-score that starts at 1.0. But the wording changes: instead of stating that robots.txt disallows AI search crawlers, the deduction reads that robots.txt is erroring, so they are treated as disallowed. The per-class block defects are suppressed entirely in that state, because every crawler then reads as disallowed with no rule attached, and raising them would invent a Disallow line that does not exist. A single defect called robots_unavailable, severity major, titled robots.txt is failing, carries the finding instead. The bot access matrix marks the same rows as blocked with robots.txt failing rather than as blocked by a rule. That distinction between a measurement and an assumption is the same one behind a user agent is a claim, not an identity, and the same reason our scanner publishes what it is.

  • 200 to 299: kind parsed The body is handed to parseRobotsTxt and the rules are evaluated per crawler token.
  • 300 to 399: resolved before the policy runs The fetch layer follows redirects manually with a cap of 5 hops, matching the at least five in section 2.3.1.2.
  • 400 to 499 including 429: kind allow_all Matches RFC 9309 section 2.3.1.3. Diverges from Google, which excludes 429 from that rule by name.
  • 500 and above: kind assume_disallow Matches RFC 9309 section 2.3.1.4. Raises the robots_unavailable defect and costs 0.4 per penalised purpose class.
  • Network error, timeout or budget exhausted: kind allow_all Section 2.3.1.4 calls this unreachable and requires complete disallow. Lantad treats it as unrestricted and says so in the note.
Every path a robots.txt fetch can take through Lantad's scanner, and the policy it selects. Read from core/src/robots.ts and core/src/pipeline.ts in this repository on 29 July 2026. These are settings, not measurements.

What to check on your own site, and what a scan cannot tell you

The check itself is one request and it is not the interesting part. Fetch your own robots.txt and read the status line. If it is 200, read the body and confirm it is the file you think it is rather than a soft 404 or an HTML error page served with a 200, which is common and which the parser will happily read as a file with no rules. If it is anything else, you have found the thing this post is about, and the direction of the problem depends on the first digit.

The interesting part is that a single check is a snapshot and this failure is usually intermittent. A robots.txt that returns 503 under load is fine every time you look at it and broken during the traffic spike, which is precisely when crawlers are also most likely to arrive. There is no way to see that from outside with one fetch, and there is no way to see it from inside either unless your logging separates requests for that one path. Two things are worth doing about it and neither is a purchase. Add /robots.txt to whatever already pings your homepage, so the file has its own uptime line rather than inheriting the site's. And look for it in your access logs by path, counting non-200 responses, because the file is small enough that nobody notices it failing.

There are also limits worth stating plainly. An external scan can tell you the status your server returned to one request from one address at one moment, which is what the robots.txt tester reports per crawler token. It cannot tell you what your server returns to a real crawler from a real crawler network, because that is a different client with a different reputation hitting possibly different edge rules, and it cannot tell you what any crawler already has cached from before your file broke. Under section 2.4 that cached copy can outlive the 24 hour ceiling for as long as the file stays unreachable, so a correct answer today does not describe what crawlers are currently acting on.

Which is a specific instance of a general point about generative engine optimisation that is worth ending on. The measurable and the decisive are not the same set. A status code is measurable and decisive, which makes it worth checking first. Whether a crawler honoured what it read is decisive and not measurable from outside, which is why the tokens that never appear in your logs stay invisible however carefully you look. Between those sits the layer most sites actually lose on, which is whether the page a crawler receives contains the text a browser shows: that is prose parity, and what GPTBot sees returns the received text so you can read it yourself. Get the status code right first, because a 503 on one file makes every other question moot, and the per crawler access view will show you which tokens are affected once it is.

Sample Illustrative, not a measurement of any real site.

GET /robots.txt, two requests, same host

  • GET /robots.txt at low traffic 200, 412 bytes, parsed
  • Rules read for GPTBot Allow, no matching Disallow
  • GET /robots.txt during a traffic spike 503 from the origin
  • Policy a conforming crawler must select complete disallow, section 2.3.1.4
  • What a single scan an hour later reports 200, no problem found
A robots.txt that fails only under load, and the same file checked twice. Illustrative of the intermittent failure described above, not a capture of any real site.

Related

Common questions

Does a 404 on robots.txt block AI crawlers?

No, it does the opposite. RFC 9309 section 2.3.1.3 classes a status in the 400 to 499 range as unavailable, and states that the crawler may then access any resources on the server. A deleted robots.txt permits everything, including any crawler you had previously disallowed.

What happens to crawlers when robots.txt returns 503?

RFC 9309 section 2.3.1.4 says the file is undefined and the crawler must assume complete disallow, which closes the whole origin. Google's own documentation describes a softer path: it stops crawling for 12 hours, then uses your last good robots.txt for 30 days, then behaves as if there is no file at all.

Is 429 on robots.txt treated as an error or as a missing file?

It depends on whose document you read. RFC 9309 puts 429 in the 400 to 499 range with no exception, so a crawler may access any resource. Google's robots.txt documentation states that its crawlers treat all 4xx errors except 429 as if a valid file did not exist, excluding it by name. OpenAI and Anthropic publish nothing on the question.

How long can a crawler use a cached copy of my robots.txt?

RFC 9309 section 2.4 says crawlers should not use a cached version for more than 24 hours, unless the robots.txt file is unreachable. Once it is unreachable that ceiling no longer applies, which is what makes Google's documented 30 day fallback to your last good file conformant.

See what AI can read on your site

Run a free scan and get a graded report of exactly what AI crawlers can and cannot read, with ranked fixes.