# Traps already paid for

| Trap | How it shows |
|---|---|
| Paging that lies | 25 of 100 files and the recipe looks healthy |
| An undeclared ceiling | ask 250, get 100, no error |
| A WAF answers every address | a real and an invented address both give 202; check a built address in a browser |
| A cursor that does not advance | the second page equals the first; compare ids |
| An unknown enum value substitutes | `feature=x` answers 200 with something else inside; check identity of ids, not meaning |
| A list that is an object | `each` runs once over the object, every `{item.x}` misses, zero files, no error |
| Markup selector on JSON | a non-markup answer gives zero, not a refusal; zero shows only on the counter |
| `contains` is case sensitive | `<IMG` does not match `<img` |
| A rate limit per application key | ask as little as you can; read `x-ratelimit-*` in `fetch` headers |
| 429 without Retry-After | the pause is in `x-ratelimit-reset` |
| A site answering only a browser session | plain client 403, the same request with the program's browser cookies 200 - `ask` plus `session` in the format |
| Files given only to a browser | `fetch` of the files 403 with and without `session`, `heads` answers with `through: browser`: write the recipe as usual, the download asks the browser for such files too. The run's report counts them in `heads.through_browser` |
| Files of one page from two places | declaration and handler announce different files and the page order breaks |
| A reference counted the same way as the recipe | it misses in the same place; count from the site's own fields |
| A Cloudflare wall | NeoDownloader's fetcher switches to its second client by itself; measure with `fetch`, not with another tool |
| A site slowing down instead of refusing | 0.4 s becomes 17 s, still 200: a run looks hung while it works; numbers taken then are about the throttling |
| A date into a name | an ISO date with colons breaks on Windows: use `"as": "date"` |
| `:has()` in `css` | the engine is lxml's cssselect: `li:has(a[href*='/x/'])` does not parse - `INVALID_VALUE` with its words. Write it as `xpath`: `//li[a[contains(@href, '/x/')]]` |
| A parameter you cannot switch | a run uses the defaults unless `params` says otherwise; a recipe that only ever ran with its default has one of its two branches untested |
