Some endpoints only return `OK` when a trailing slash is in the URL?
I have a script that goes through the https://pokeapi.co/api/v2/pokemon endpoint, and gets some metadata about each Pokemon by using the url field of each result. This field always has a trailing /, which seems to have issues as of recently? Some Pokemon, such as Chlorophyll, return just the string OK when there is a trailing slash. I thought maybe I was being rate-limited, but removing the slash makes it work? This also only happens on some Pokemon (IDs 1-186 did not have this issue)
This was not an issue a few weeks ago, I'm not really sure when this was introduced
Steps to Reproduce:
- Visit
https://pokeapi.co/api/v2/pokemon/187and see the data - Visit
https://pokeapi.co/api/v2/pokemon/187/and see justOK
Screenshots:
I've confirmed that this also happens in other endpoints too, not just pokemon. https://pokeapi.co/api/v2/pokemon-species/221/ has the same behavior
Hi! I don't get that behavior. I suspect it is determined by Cloud flare, has always been like this for you? Or it used to work properly?
Hi! I don't get that behavior. I suspect it is determined by Cloud flare, has always been like this for you? Or it used to work properly?
It used to work properly. I wrote a script several weeks ago to go through and get the data I needed from the API and save it locally. I'm now running the script again after not running it for about a week or so since there's some new data I need, and now this behavior happens
So it's a change that happened relatively recently
The only difference on my end between now and the last time I ran the script is a change in what network I'm on (I'm at a different house now than I was then). But that shouldn't be the cause of something like this. Just to sanity check though, I disconnected from the network and checked on my phone and the same behavior happens there, so it definitely seems like something changed on the servers side
I suspect it is determined by Cloud flare
Sorry for the triple reply. I decided to check this, and it does look related to Cloudflare. It looks like there's something wrong with your cache?
I checked the headers for the known bad examples:
curl -I https://pokeapi.co/api/v2/pokemon/187
HTTP/2 200
date: Sun, 31 Aug 2025 03:05:21 GMT
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=86400, s-maxage=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"3563a-XqiR7JroUuNob8RICfRN823A2Yc"
function-execution-id: 1nbx20c0tmtq
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: 4059f0c6f8cc3b432268a40ca78aee8c
x-country-code: US
x-orig-accept-language: en-US,en;q=0.9
x-powered-by: Express
x-served-by: cache-chi-klot8100107-CHI
x-cache: HIT
x-cache-hits: 0
x-timer: S1752046310.245730,VS0,VE1
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=wzxQ13Mw2To7%2BHYJQdDhtMkCwSRxvbfDUlncp9YzlTHVvhbKCfWfvtL0%2FqrDfapb1dgx3bt2z1kbU40D5PFCv4MA2fcTpF7mpL8lKL6BX4L2Fdrv"}]}
age: 14589
cf-cache-status: HIT
cf-ray: 97794e461e794d9a-JAX
curl -I https://pokeapi.co/api/v2/pokemon/187/
HTTP/2 200
date: Sun, 31 Aug 2025 03:05:24 GMT
content-type: text/plain; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=432000, s-maxage=432000
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"2-nOO9QiTIwXgNtWtBJezz8kv3SLc"
function-execution-id: t7hwn8jvyrlh
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: 9c5f7958878382424bc305a7698dd4f3
x-country-code: US
x-orig-accept-language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7
x-powered-by: Express
x-served-by: cache-iad-kiad7000064-IAD
x-cache: HIT
x-cache-hits: 0
x-timer: S1756350648.213939,VS0,VE1
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=ZUk54FXKiDkVQIounCzi917ucl%2Bfmy7FB%2FCHULDXz%2BCUY8ayXRU8ZpuEuIF0JhY3N0%2F6MlJwaqzxMRDP1fctcD7b%2FY9L%2FlCvcCLvfqe9EwQ%2Bh5Nl"}]}
age: 118589
cf-cache-status: HIT
cf-ray: 97794e575c90c25a-JAX
You can see some notable differences here in the responses:
- There's differing cache control. One has
max-age=86400(1 day) whereas the other hasmax-age=432000(5 days) - The etags differ (because of the different content)
Compared to known working examples:
curl -I https://pokeapi.co/api/v2/pokemon/1
HTTP/2 200
date: Sun, 31 Aug 2025 03:07:24 GMT
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=86400, s-maxage=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"3ef7e-dtH2kyIZxKG0mcap0bBKsRCixno"
function-execution-id: yv5nxnme7ci2
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: c209e6a8293e56091c870b8ef10d03ac
x-country-code: US
x-orig-accept-language: en-US,en;q=0.9
x-powered-by: Express
x-served-by: cache-gnv1820023-GNV
x-cache: HIT
x-cache-hits: 0
x-timer: S1751724188.518917,VS0,VE1
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=c33%2BgUJ9VrM3UFHlhphUJzi71kibUXR2RBouNwM6dNDNzIS3SIOYuZOH2iA4tG5IksygHUYcQktzs2olaibt9rjXoFryAoRLt1dZ5cjTJWMO1Ovp"}]}
age: 45147
cf-cache-status: HIT
cf-ray: 97795146990732f2-JAX
curl -I https://pokeapi.co/api/v2/pokemon/1/
HTTP/2 200
date: Sun, 31 Aug 2025 03:07:27 GMT
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=86400, s-maxage=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"3ef7e-dtH2kyIZxKG0mcap0bBKsRCixno"
function-execution-id: 7ui55taeprho
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: adeb48f7e18d0be902ee74cabc05d10c
x-country-code: GB
x-orig-accept-language: en-US
x-powered-by: Express
x-served-by: cache-lcy-eglc8600048-LCY
x-cache: HIT
x-cache-hits: 0
x-timer: S1752743806.480667,VS0,VE1
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=QAcZlP20%2F5XyPhtw0MQBc%2Fg2FrO4bPpznNuZ3b79veWRaRj%2BIUumUd%2FntUWqEfH5vhagEGXkfqQl6OI7XzZkxw4UVw7g17HSAi%2FDDMFFRYexNsy9"}]}
age: 32125
cf-cache-status: HIT
cf-ray: 97795157193f68ca-JAX
These have identical etags, cache controls, etc.
It looks like at some point your Cloudflare caching rules got updated, and now some things have incorrect cache control settings and are serving badly cached content?
I'm not sure how you guys have this setup on your end but it seems like a cache purge and then rechecking the cache rules should be all that needs to be done to fix this?
Or maybe have Cloudflare redirect requests that have the trailing slash to the endpoint without the trailing slash, to get around the issue entirely?
I don't get that behavior
If by "don't get" you mean you can't replicate it, then I suspect this is because we are being served cached contents from 2 different regions. You might be getting served the correct contents if they were cached properly where you are, but it definitely seems like something is wrong with the cache in at least a few regions. So far it looks like the only bad caches are coming from the US, but there may be other regions affected as well
Just for reference this is the response I get:
curl -I https://pokeapi.co/api/v2/pokemon/187
HTTP/2 200
date: Sun, 31 Aug 2025 03:19:47 GMT
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=86400, s-maxage=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"3563a-XqiR7JroUuNob8RICfRN823A2Yc"
function-execution-id: 35ec5scnbw0h
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: 96ca676c2384a53311db3912849a57ab
x-country-code: KR
x-orig-accept-language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
x-powered-by: Express
x-served-by: cache-icn1450043-ICN
x-cache: HIT
x-cache-hits: 0
x-timer: S1756165848.171622,VS0,VE660
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=PJWx2W%2FWL%2B7%2Bjhc5TDw4rcLoJEs9j4HiAvrnPchpARQWByy81ttj9ZH6nmQweyar9dLqDJ1PyjTGKirJSv%2FBUNiYhC9YYGF22vI%3D"}]}
age: 84480
cf-cache-status: HIT
cf-ray: 9779636b8d31d417-KIX
curl -I https://pokeapi.co/api/v2/pokemon/187/
HTTP/2 200
date: Sun, 31 Aug 2025 03:20:33 GMT
content-type: application/json; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=86400, s-maxage=86400
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"3563a-XqiR7JroUuNob8RICfRN823A2Yc"
function-execution-id: vm4skedhnyek
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: e5993f76bdd3a19f5a7940f5409b8cd6;o=1
x-country-code: GB
x-orig-accept-language: en-US,en;q=0.9
x-powered-by: Express
x-served-by: cache-lcy-eglc8600023-LCY
x-cache: HIT
x-cache-hits: 0
x-timer: S1752846760.352098,VS0,VE1
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=04tIb3zKKP9aUzRpJQcA3jqWtDIGA%2BKOyAhC%2Fr0CbzxXOzBCiPVgvHFtZgwPpm5mPRbzDi46nffk3zOGoOQihi%2FuK7jG5NOtpCo%3D"}]}
age: 73963
cf-cache-status: HIT
cf-ray: 977964893b20d422-KIX
I'll decide to do a purge later on, I'm a bit busy now.
Feel free to use staging.pokeapi.co in the meantime, but don't fire too many requests please. We don't have any cloudflare cache in front of that.
Just as a test I purged https://pokeapi.co/api/v2/pokemon-species/221/. Could you tell me the outcome on your side? On my side everything works well after and worked well before.
https://pokeapi.co/api/v2/pokemon-species/221/ still returns OK in my case:
curl -I https://pokeapi.co/api/v2/pokemon-species/221/
HTTP/2 200
date: Sun, 31 Aug 2025 03:26:32 GMT
content-type: text/plain; charset=utf-8
access-control-allow-origin: *
cache-control: public, max-age=432000, s-maxage=432000
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
etag: W/"2-nOO9QiTIwXgNtWtBJezz8kv3SLc"
function-execution-id: r3sy9iicckh2
server: cloudflare
strict-transport-security: max-age=31556926
x-cloud-trace-context: 28cde719dfdc46e5ac293ba3304c135d
x-country-code: US
x-orig-accept-language: en-US
x-powered-by: Express
x-served-by: cache-chi-klot8100046-CHI
x-cache: HIT
x-cache-hits: 0
x-timer: S1756610689.607089,VS0,VE2
vary: Accept-Encoding,cookie,need-authorization, x-fh-requested-host, accept-encoding
alt-svc: h3=":443"; ma=86400
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Om636lWJwBsZ%2BZLyyoO2kFuG49TW5RNc5%2FIuGiythavU3hrwVDdZj4XkOv%2Fyjlk9QSrAvEsozXqvcd4CJsNFzVagGI0w9ezGv%2FmCky%2B%2BLVyiL1Hi"}]}
cf-cache-status: HIT
cf-ray: 97796d4a5b84c25a-JAX
curl https://pokeapi.co/api/v2/pokemon-species/221/
OK%
That definitely seems to confirm it, you're getting cache results that line up with the other known good examples I have, and your regions are outside of the US so we're being served different caches
So far I've been able to work around this by just trimming the URL in my script, so I don't think I'll need to hit the staging API 👍 it's good to know that's there though!
I'm experiencing this issue as well. My current workaround is to add superfluous query parameters to bypass CloudFlare's cache when a request fails the first time.
I'm experiencing this issue as well. My current workaround is to add superfluous query parameters to bypass CloudFlare's cache when a request fails the first time.
I've been reliably able to query every API endpoint without issue so long as I trim the trailing slash from the URL. That should help reduce the number of calls you're making as well I think (since you don't have to rely on a failed request to add query params)