Table of contents
If your robots.txt says User-agent: * followed by Disallow: /, every crawler that obeys the file is told to stay off your whole site. It takes one line to cause and about a minute to find, and Google's Page indexing report will label the result "blocked by robots.txt" once it notices. This guide shows how to confirm the line is live, where it came from, and the five-line deploy step that stops it coming back.
Quick summary
Run curl -s https://yoursite.com/robots.txt. If the first group is User-agent: * with Disallow: / and nothing allowing /, the file is blocking everything. Delete the line, redeploy, and add the guard below so the next deploy cannot put it back.
| Where it came from | How to tell | Fix |
|---|---|---|
| Staging file promoted by a deploy | Production file is byte-identical to staging's | Serve robots.txt from per-environment config |
| WordPress Settings > Reading box ticked | noindex,nofollow in the page <head>, robots.txt looks normal | Untick the box |
Framework robots file keyed to the wrong variable | Local build is fine, deployed file is not | Key it to the deploy environment |
| Host preview rules on the custom domain | Rule appears only on one hostname | Check the host's per-domain settings |
robots.txt returns 5xx | Status is 500 to 599 | Fix the server error |
Why one line blocks everything
According to RFC 9309, a crawler uses the group that names it, and falls back to the * group only if no group names it. Within a group, the most specific matching rule wins, and Disallow: / matches every path. So a lone User-agent: * group with Disallow: / shuts out every crawler that has no group of its own.
The reverse also holds, and it corrects a common assumption. I parsed a file with a * block plus a separate GPTBot group that allows / using Python's urllib.robotparser. Result: GPTBot may fetch /blog/, ClaudeBot and Googlebot may not. A named Allow group is not moot. It only helps the bots you named.
One more RFC rule bites here. If robots.txt cannot be fetched because of a server error (a 5xx status), the RFC says the crawler "MUST assume complete disallow". A broken deploy that makes /robots.txt return a 500 blocks the site as effectively as the line does.
Step 1: Confirm what crawlers actually get
curl -sI https://yoursite.com/robots.txt | head -n 5
curl -s https://yoursite.com/robots.txt
Look for three things: a 200 status, a text/plain content type, and the group above. Check both www and the bare domain, because a preview or staging rule can sit on one hostname only.
Blocked pages are not removed from search. According to Google's robots.txt introduction, the file is not a mechanism for keeping a page out of Google, so a blocked URL can still be listed, usually with no description. Search Console shows that state as "Indexed, though blocked by robots.txt".
Step 2: Find where the line came from
A staging file promoted by a deploy. Teams often keep a blanket-disallow robots.txt on staging on purpose. If the file lives in the repository and is copied by the build, production gets it. Compare hashes: curl -s https://staging.yoursite.com/robots.txt | sha256sum against production.
WordPress. The checkbox is under Settings > Reading > Search engine visibility > Discourage search engines from indexing this site. According to the WordPress documentation, since version 5.3 ticking it adds <meta name='robots' content='noindex,nofollow' /> to the page head. Up to version 5.2 it made robots.txt return Disallow: /. The current do_robots() source writes Disallow: /wp-admin/ and an Allow for admin-ajax.php, and only passes the "public" flag to the robots_txt filter. So on a current install a ticked box does not put Disallow: / in robots.txt. A plugin or theme using that filter can. If the file is blocking and the box is clear, look for a plugin that writes robots.txt. ThinkRank has a robots.txt editor in one plugin, so you can see and change the real file in one place.
A framework robots file. In Next.js, app/robots.ts returns the rules object, and the Next.js docs example shows allow: '/' with a narrower disallow. A common bug is deciding "is this production?" with a variable that is set the same way on every deploy. According to Vercel's system environment variable docs, VERCEL_ENV is production, preview or development, which is the variable to branch on:
// app/robots.ts
export default function robots() {
const live = process.env.VERCEL_ENV === 'production'
return {
rules: live ? { userAgent: '*', allow: '/' } : { userAgent: '*', disallow: '/' },
sitemap: 'https://yoursite.com/sitemap.xml',
}
}
If you branch on something else, test that variable's value in a real production build before you trust it.
Host preview rules. If the rule shows on one hostname only, look in your host's settings for that domain, not in your code.
Step 3: Guard the deploy
This step runs against the live URL after every deploy and fails the job if production blocks everything. I tested it on four files, 30 October 2026:
| Test file | Guard result |
|---|---|
Lone User-agent: * + Disallow: / | FAIL, exit 1 |
Same block plus a GPTBot group with Allow: / | FAIL, exit 1 |
WordPress-style file (Disallow: /wp-admin/, a Sitemap line) | ok, exit 0 |
Lowercase user-agent: * and disallow: / with trailing spaces | FAIL, exit 1 |
#!/bin/sh
# usage: ./robots-guard.sh https://yoursite.com/robots.txt
f=$(mktemp); curl -fsS "$1" -o "$f" || exit 2
if tr -d '\r' < "$f" | grep -Pzoi '(?m)^user-agent:[ \t]*\*[ \t]*\n(?:(?:allow|disallow|crawl-delay|#)[^\n]*\n)*?disallow:[ \t]*/[ \t]*(?:#[^\n]*)?(?:\n|$)' >/dev/null; then
echo "FAIL: robots.txt disallows / for *"; exit 1
fi
echo ok
It exits 2 when curl fails, so a 404 or 5xx fails the build too (checked against a real 404). It is deliberately simple: it only catches a * group containing Disallow: /, and it will also flag a group that pairs it with Allow: /$, which is the safe direction. For a full regression gate on a whole site, see Gate AI readiness in CI.
Step 4: Verify
Run the scan first. npx aiscan-cli yoursite.com reports check D1 (robots.txt present and sane) under discoverability and B2 (explicit AI bot rules) under bot access. Then confirm by hand with curl -s https://yoursite.com/robots.txt and the guard script above.
One thing to know before you trust a green D1. I scanned mail.google.com on 30 October 2026. Its robots.txt is a * group of Disallow: / with Allow: /$ and Allow: /mail/$ lines, plus a Sitemap: line.
| Check | Status | Evidence AIScan printed |
|---|---|---|
| D1 robots.txt present and sane | pass | 200 OK, 130 bytes, declares Sitemap |
| B2 explicit AI bot rules | fail | 0 known AI agent(s) addressed in robots.txt |
That is one site, and its file allows the root, so it is not the lone Disallow: / case. According to AIScan's Sitemap-line study, D1 wants a 200, no catch-all User-agent: * block and a Sitemap: URL. Treat D1 as one signal, and keep the guard script as the one that fails your build.
According to the AI crawler declaration census, 11 of 451 parsed files (2.4%) carried a blanket User-agent: * full block. Some are on purpose. The fix is the same: decide it was meant, or remove it.
Maintenance
- Run the guard after every deploy, not only on releases that touch robots.txt.
- Keep staging protected by a login or an
X-Robots-Tagheader, not by a robots.txt that can be copied by accident. - After you fix it, request a recrawl in Search Console and allow days for the status to clear.
- What to write on purpose is covered in the robots.txt starter for AI crawlers, and the status and content type in Serve robots.txt with the right status and content type.
Next step
Run npx aiscan-cli yoursite.com, check D1 and B2, then add the guard to your deploy. More fixes are in the AIScan guides, and the discoverability check page explains what D1 looks for.
Frequently asked questions
Why does my robots.txt say Disallow: / when I never wrote it?
It was copied or generated. The usual sources are a staging robots.txt promoted by a deploy, a framework robots file keyed to the wrong environment variable, a host's preview-domain rules, or a plugin that writes the file. Compare production with staging, then search your repo and plugins for the line.
Google Search Console says "Indexed, though blocked by robots.txt". What do I do?
Remove the blocking rule, then request a recrawl. Google's robots.txt introduction says the file is not a way to keep a page out of Google, so a blocked URL can still be listed without a description. The status clears after Google fetches the page again, which can take days.
I unticked Discourage search engines in WordPress and my site is still blocked. Why?
The box adds a noindex,nofollow meta tag on current WordPress, so a robots.txt block is coming from somewhere else, usually a plugin or a hand-edited file. Fetch /robots.txt, find the Disallow: / line, and check which plugin writes the file.
My robots.txt returns a 500 error. Is my site blocked?
Effectively yes. RFC 9309 says that when robots.txt is unreachable because of a server error, a crawler must assume complete disallow. Fix the server error so /robots.txt returns 200 with plain text.
Does Allow: / under GPTBot override Disallow: / under User-agent: *?
For GPTBot, yes. A crawler uses the group that names it and falls back to the * group only when none does. I parsed such a file with Python's robotparser: GPTBot could fetch /blog/, ClaudeBot and Googlebot could not.
Does AIScan fail a robots.txt that blocks everything?
Not reliably on its own. On 30 Oct 2026 I scanned mail.google.com, whose * group is Disallow: / with Allow: /$ lines and a Sitemap line, and D1 passed while B2 failed. That file allows the root, so it is not the lone Disallow: / case. Use the guard script as the gate.
How do I keep staging out of search without robots.txt?
Put staging behind a login or send an X-Robots-Tag header. A robots.txt on staging works until a deploy copies it to production, which is how this problem usually starts.
How do I stop Disallow: / coming back after a deploy?
Run a check against the live robots.txt after every deploy and fail the job if the * group disallows /. The guard script in this post exits 1 on a block and 2 when robots.txt cannot be fetched.

About the author
M Asif Rahman
Entrepreneur, curious about AI
I have been building companies for a long time, and lately most of my curiosity goes to AI. AIScan is a small personal project I built on a flight from Dubai to Narita. I use it to understand how ready the web is for AI agents, and I share what the scans teach me.
Related guides
AI readiness setup guide by platform (2026)
Verified 17, 18, 20 and 22 October 2026. Updated on 22 October 2026. An AIready site needs six things: a robots.txt that names AI crawlers D1, B2, a sitemap D2, a declared feed E5, an llms.txt C2,…
llms.txt vs robots.txt vs sitemap.xml in 2026: Six Files, Six Jobs
Verified 4 September 2026. Every figure below was measured or fetched on that date. Three files keep getting compared as if they were competing for the same job: robots.txt, sitemap.xml and llms.txt.…
Fix: A WordPress Security Plugin Is Blocking GPTBot, ClaudeBot and PerplexityBot
If your robots.txt allows GPTBot, ClaudeBot and PerplexityBot but your logs show a wall of 403 for those same names, robots.txt is not the problem. A rule that runs before WordPress is. This guide…
